Merge branch 'master' into cmake

This commit is contained in:
Sam Edwards 2018-10-13 16:15:35 -06:00
commit ea1b50a522
46 changed files with 1190 additions and 248 deletions

View File

@ -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
=============

View File

@ -1,2 +1,3 @@
#include "filename_ext.cxx"
#include "globPattern_ext.cxx"
#include "textEncoder_ext.cxx"

View File

@ -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) {
}

View File

@ -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;
}

View File

@ -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

View File

@ -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();
}
}
/**

View File

@ -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) {

View File

@ -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 &copy);
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 {

View File

@ -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());
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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.

View File

@ -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",

View File

@ -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();
}

View File

@ -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.

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}
/**
*
*/

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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()) {

View File

@ -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)) {

View File

@ -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();

View File

@ -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__;

View File

@ -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;

View File

@ -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>;

View File

@ -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;

View File

@ -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

View File

@ -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
}
}

View File

@ -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;

View File

@ -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
}

View File

@ -62,8 +62,6 @@ private:
PN_stdfloat _lifespan;
bool _alive;
int _index;
LPoint3 _last_position;
};
#include "baseParticle.I"

View File

@ -68,7 +68,7 @@ make_off() {
*/
CPT(RenderAttrib) ColorAttrib::
make_default() {
return make_off();
return make_vertex();
}
/**

View File

@ -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();

View File

@ -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.

View File

@ -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

View File

@ -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,

View File

@ -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;
}

View File

@ -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);

View File

@ -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)

View File

@ -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]

View File

@ -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)