Merge remote-tracking branch 'upstream/master'

This commit is contained in:
John Cote 2021-07-07 16:18:31 -04:00
commit fe157b00af
No known key found for this signature in database
GPG Key ID: E3442FF71E9C1C01
63 changed files with 862 additions and 275 deletions

View File

@ -307,7 +307,9 @@ get_slotted_function_def(Object *obj, Function *func, FunctionRemap *remap,
string method_name = func->_ifunc.get_name();
bool is_unary_op = func->_ifunc.is_unary_op();
if (method_name == "operator +") {
if (method_name == "operator +" ||
method_name == "__add__" ||
method_name == "__radd__") {
def._answer_location = "nb_add";
def._wrapper_type = WT_binary_operator;
return true;
@ -319,13 +321,17 @@ get_slotted_function_def(Object *obj, Function *func, FunctionRemap *remap,
return true;
}
if (method_name == "operator -") {
if (method_name == "operator -" ||
method_name == "__sub__" ||
method_name == "__rsub__") {
def._answer_location = "nb_subtract";
def._wrapper_type = WT_binary_operator;
return true;
}
if (method_name == "operator *") {
if (method_name == "operator *" ||
method_name == "__mul__" ||
method_name == "__rmul__") {
def._answer_location = "nb_multiply";
def._wrapper_type = WT_binary_operator;
return true;
@ -337,37 +343,47 @@ get_slotted_function_def(Object *obj, Function *func, FunctionRemap *remap,
return true;
}
if (method_name == "__truediv__") {
if (method_name == "__truediv__" ||
method_name == "__rtruediv__") {
def._answer_location = "nb_true_divide";
def._wrapper_type = WT_binary_operator;
return true;
}
if (method_name == "__floordiv__") {
if (method_name == "__floordiv__" ||
method_name == "__rfloordiv__") {
def._answer_location = "nb_floor_divide";
def._wrapper_type = WT_binary_operator;
return true;
}
if (method_name == "operator %") {
if (method_name == "operator %" ||
method_name == "__mod__" ||
method_name == "__rmod__") {
def._answer_location = "nb_remainder";
def._wrapper_type = WT_binary_operator;
return true;
}
if (method_name == "operator <<") {
if (method_name == "operator <<" ||
method_name == "__lshift__" ||
method_name == "__rlshift__") {
def._answer_location = "nb_lshift";
def._wrapper_type = WT_binary_operator;
return true;
}
if (method_name == "operator >>") {
if (method_name == "operator >>" ||
method_name == "__rshift__" ||
method_name == "__rrshift__") {
def._answer_location = "nb_rshift";
def._wrapper_type = WT_binary_operator;
return true;
}
if (method_name == "operator ^") {
if (method_name == "operator ^" ||
method_name == "__xor__" ||
method_name == "__rxor__") {
def._answer_location = "nb_xor";
def._wrapper_type = WT_binary_operator;
return true;
@ -379,13 +395,17 @@ get_slotted_function_def(Object *obj, Function *func, FunctionRemap *remap,
return true;
}
if (method_name == "operator &") {
if (method_name == "operator &" ||
method_name == "__and__" ||
method_name == "__rand__") {
def._answer_location = "nb_and";
def._wrapper_type = WT_binary_operator;
return true;
}
if (method_name == "operator |") {
if (method_name == "operator |" ||
method_name == "__or__" ||
method_name == "__ror__") {
def._answer_location = "nb_or";
def._wrapper_type = WT_binary_operator;
return true;
@ -1896,16 +1916,8 @@ write_module_class(ostream &out, Object *obj) {
break;
case WT_one_param:
case WT_binary_operator:
case WT_inplace_binary_operator:
// PyObject *func(PyObject *self, PyObject *one)
{
int return_flags = RF_err_null;
if (rfi->second._wrapper_type == WT_inplace_binary_operator) {
return_flags |= RF_self;
} else {
return_flags |= RF_pyobject;
}
bool all_nonconst = true;
for (FunctionRemap *remap : def._remaps) {
if (remap->_const_method) {
@ -1918,20 +1930,7 @@ write_module_class(ostream &out, Object *obj) {
out << "//////////////////\n";
out << "static PyObject *" << def._wrapper_name << "(PyObject *self, PyObject *arg) {\n";
out << " " << cClassName << " *local_this = nullptr;\n";
if (rfi->second._wrapper_type != WT_one_param) {
// WT_binary_operator means we must return NotImplemented, instead
// of raising an exception, if the this pointer doesn't match.
// This is for things like __sub__, which Python likes to call on
// the wrong-type objects.
out << " DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **)&local_this);\n";
if (all_nonconst) {
out << " if (local_this == nullptr || DtoolInstance_IS_CONST(self)) {\n";
} else {
out << " if (local_this == nullptr) {\n";
}
out << " Py_INCREF(Py_NotImplemented);\n";
out << " return Py_NotImplemented;\n";
} else if (all_nonconst) {
if (all_nonconst) {
out << " if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_"
<< ClassName << ", (void **)&local_this, \"" << ClassName
<< "." << methodNameFromCppName(fname, "", false) << "\")) {\n";
@ -1944,19 +1943,85 @@ write_module_class(ostream &out, Object *obj) {
string expected_params;
write_function_forset(out, def._remaps, 1, 1, expected_params, 2, true, true,
AT_single_arg, return_flags, false, !all_nonconst);
AT_single_arg, RF_err_null | RF_pyobject, false, !all_nonconst);
if (rfi->second._wrapper_type != WT_one_param) {
out << " Py_INCREF(Py_NotImplemented);\n";
out << " return Py_NotImplemented;\n";
out << " if (!_PyErr_OCCURRED()) {\n";
out << " return Dtool_Raise_BadArgumentsError(\n";
output_quoted(out, 6, expected_params);
out << ");\n";
out << " }\n";
out << " return nullptr;\n";
out << "}\n\n";
}
break;
case WT_binary_operator:
case WT_inplace_binary_operator:
// PyObject *func(PyObject *self, PyObject *one)
{
int return_flags = RF_err_null;
if (rfi->second._wrapper_type == WT_inplace_binary_operator) {
return_flags |= RF_self;
} else {
out << " if (!_PyErr_OCCURRED()) {\n";
out << " return Dtool_Raise_BadArgumentsError(\n";
output_quoted(out, 6, expected_params);
out << ");\n";
out << " }\n";
out << " return nullptr;\n";
return_flags |= RF_pyobject;
}
bool forward_all_nonconst = true;
bool reverse_all_nonconst = true;
set<FunctionRemap *> forward_remaps;
set<FunctionRemap *> reverse_remaps;
for (FunctionRemap *remap : def._remaps) {
std::string fname = remap->_cppfunc->get_simple_name();
if (fname.compare(0, 3, "__r") == 0 && fname != "__rshift__") {
reverse_remaps.insert(remap);
if (remap->_const_method) {
reverse_all_nonconst = false;
}
} else {
forward_remaps.insert(remap);
if (remap->_const_method) {
forward_all_nonconst = false;
}
}
}
out << "//////////////////\n";
out << "// A wrapper function to satisfy Python's internal calling conventions.\n";
out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n";
out << "//////////////////\n";
out << "static PyObject *" << def._wrapper_name << "(PyObject *self, PyObject *arg) {\n";
out << " " << cClassName << " *local_this = nullptr;\n";
// WT_binary_operator means we must return NotImplemented, instead
// of raising an exception, if the this pointer doesn't match.
// This is for things like __sub__, which Python likes to call on
// the wrong-type objects.
if (!forward_remaps.empty()) {
out << " DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **)&local_this);\n";
if (forward_all_nonconst) {
out << " if (local_this != nullptr && !DtoolInstance_IS_CONST(self)) {\n";
} else {
out << " if (local_this != nullptr) {\n";
}
string expected_params;
write_function_forset(out, forward_remaps, 1, 1, expected_params, 4, true, true,
AT_single_arg, return_flags, false, !forward_all_nonconst);
out << " }\n";
}
if (!reverse_remaps.empty()) {
out << " std::swap(self, arg);\n";
out << " DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **)&local_this);\n";
if (reverse_all_nonconst) {
out << " if (local_this != nullptr && !DtoolInstance_IS_CONST(self)) {\n";
} else {
out << " if (local_this != nullptr) {\n";
}
string expected_params;
write_function_forset(out, reverse_remaps, 1, 1, expected_params, 4, true, true,
AT_single_arg, return_flags, false, !reverse_all_nonconst);
out << " }\n";
}
out << " Py_INCREF(Py_NotImplemented);\n";
out << " return Py_NotImplemented;\n";
out << "}\n\n";
}
break;

View File

@ -71,9 +71,6 @@ protected:
CFMutableArrayRef find_display_modes(int width, int height);
bool do_switch_fullscreen(CGDisplayModeRef mode);
virtual void mouse_mode_absolute();
virtual void mouse_mode_relative();
private:
NSData *load_image_data(const Filename &filename);
NSImage *load_image(const Filename &filename);

View File

@ -693,7 +693,7 @@ open_window() {
// Enable relative mouse mode, if this was requested.
if (_properties.has_mouse_mode() &&
_properties.get_mouse_mode() == WindowProperties::M_relative) {
mouse_mode_relative();
CGAssociateMouseAndMouseCursorPosition(NO);
}
_vsync_enabled = sync_video && cocoagsg->setup_vsync();
@ -747,22 +747,6 @@ close_window() {
GraphicsWindow::close_window();
}
/**
* Overridden from GraphicsWindow.
*/
void CocoaGraphicsWindow::
mouse_mode_absolute() {
CGAssociateMouseAndMouseCursorPosition(YES);
}
/**
* Overridden from GraphicsWindow.
*/
void CocoaGraphicsWindow::
mouse_mode_relative() {
CGAssociateMouseAndMouseCursorPosition(NO);
}
/**
* Applies the requested set of properties to the window, if possible, for
* instance to request a change in size or minimization status.

View File

@ -383,6 +383,11 @@ ConfigVariableFilename subprocess_window
"and is not used or needed in other environments. See "
"WindowProperties::set_subprocess_window()."));
ConfigVariableBool ime_aware
("ime-aware", false,
PRC_DESC("Set this true to show candidate strings in Panda3D rather than via "
"an OS-provided external popup window."));
ConfigVariableString framebuffer_mode
("framebuffer-mode", "",
PRC_DESC("No longer has any effect. Do not use."));

View File

@ -84,6 +84,7 @@ extern EXPCL_PANDA_DISPLAY ConfigVariableString window_title;
extern EXPCL_PANDA_DISPLAY ConfigVariableInt parent_window_handle;
extern EXPCL_PANDA_DISPLAY ConfigVariableBool win_unexposed_draw;
extern EXPCL_PANDA_DISPLAY ConfigVariableFilename subprocess_window;
extern EXPCL_PANDA_DISPLAY ConfigVariableBool ime_aware;
extern EXPCL_PANDA_DISPLAY ConfigVariableString framebuffer_mode;
extern EXPCL_PANDA_DISPLAY ConfigVariableBool framebuffer_hardware;

View File

@ -696,23 +696,6 @@ add_input_device(InputDevice *device) {
return index;
}
/**
* detaches mouse. Only mouse delta from now on.
*
*/
void GraphicsWindow::
mouse_mode_relative() {
}
/**
* reattaches mouse to location
*
*/
void GraphicsWindow::
mouse_mode_absolute() {
}
/**
* Returns whether the specified event msg is a touch message.
*

View File

@ -130,9 +130,6 @@ protected:
virtual bool do_reshape_request(int x_origin, int y_origin, bool has_origin,
int x_size, int y_size);
virtual void mouse_mode_absolute();
virtual void mouse_mode_relative();
// It is an error to call any of the following methods from any thread other
// than the window thread.
void system_changed_properties(const WindowProperties &properties);

View File

@ -1084,10 +1084,12 @@ reset() {
if (is_at_least_gl_version(4, 4) || has_extension("GL_ARB_clear_texture")) {
_glClearTexImage = (PFNGLCLEARTEXIMAGEPROC)
get_extension_func("glClearTexImage");
_glClearTexSubImage = (PFNGLCLEARTEXSUBIMAGEPROC)
get_extension_func("glClearTexSubImage");
if (_glClearTexImage == nullptr) {
if (_glClearTexImage == nullptr || _glClearTexSubImage == nullptr) {
GLCAT.warning()
<< "GL_ARB_clear_texture advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n";
<< "GL_ARB_clear_texture advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
} else {
_supports_clear_texture = true;
}
@ -13458,59 +13460,9 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
}
}
bool success = true;
if (texture_type == Texture::TT_cube_map) {
// A cube map must load six different 2-d images (which are stored as the
// six pages of the system ram image).
if (!_supports_cube_map) {
report_my_gl_errors();
return false;
}
nassertr(target == GL_TEXTURE_CUBE_MAP, false);
success = success && upload_texture_image
(gtc, needs_reload, uses_mipmaps, mipmap_bias,
GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
internal_format, external_format, component_type,
true, 0, image_compression);
success = success && upload_texture_image
(gtc, needs_reload, uses_mipmaps, mipmap_bias,
GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
internal_format, external_format, component_type,
true, 1, image_compression);
success = success && upload_texture_image
(gtc, needs_reload, uses_mipmaps, mipmap_bias,
GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
internal_format, external_format, component_type,
true, 2, image_compression);
success = success && upload_texture_image
(gtc, needs_reload, uses_mipmaps, mipmap_bias,
GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
internal_format, external_format, component_type,
true, 3, image_compression);
success = success && upload_texture_image
(gtc, needs_reload, uses_mipmaps, mipmap_bias,
GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
internal_format, external_format, component_type,
true, 4, image_compression);
success = success && upload_texture_image
(gtc, needs_reload, uses_mipmaps, mipmap_bias,
GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
internal_format, external_format, component_type,
true, 5, image_compression);
} else {
// Any other kind of texture can be loaded all at once.
success = upload_texture_image
(gtc, needs_reload, uses_mipmaps, mipmap_bias, target,
target, internal_format, external_format,
component_type, false, 0, image_compression);
}
bool success = upload_texture_image
(gtc, needs_reload, uses_mipmaps, mipmap_bias, target,
internal_format, external_format, component_type, image_compression);
if (gtc->_generate_mipmaps && _glGenerateMipmap != nullptr &&
!image.is_null()) {
@ -13571,21 +13523,13 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
/**
* Loads a texture image, or one page of a cube map image, from system RAM to
* texture memory.
*
* texture_target is normally the same thing as page_target; both represent
* the GL target onto which the texture image is loaded, e.g. GL_TEXTURE_1D,
* GL_TEXTURE_2D, etc. The only time they may differ is in the case of cube
* mapping, in which case texture_target will be target for the overall
* texture, e.g. GL_TEXTURE_CUBE_MAP, and page_target will be the target for
* this particular page, e.g. GL_TEXTURE_CUBE_MAP_POSITIVE_X.
*/
bool CLP(GraphicsStateGuardian)::
upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
bool uses_mipmaps, int mipmap_bias,
GLenum texture_target, GLenum page_target,
GLenum texture_target,
GLint internal_format,
GLint external_format, GLenum component_type,
bool one_page_only, int z,
Texture::CompressionMode image_compression) {
// Make sure the error stack is cleared out before we begin.
clear_my_gl_errors();
@ -13635,29 +13579,32 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
// saving on texture memory fragmentation.
if (GLCAT.is_debug()) {
SparseArray pages = gtc->get_image_modified_pages(0);
if (num_ram_mipmap_levels == 0) {
if (tex->has_clear_color()) {
GLCAT.debug()
<< "clearing texture " << tex->get_name() << ", "
<< width << " x " << height << " x " << depth << ", z = " << z
<< width << " x " << height << " x " << depth << ", pages " << pages
<< ", uses_mipmaps = " << uses_mipmaps << ", clear_color = "
<< tex->get_clear_color() << "\n";
} else {
GLCAT.debug()
<< "not loading NULL image for texture " << tex->get_name()
<< ", " << width << " x " << height << " x " << depth
<< ", z = " << z << ", uses_mipmaps = " << uses_mipmaps << "\n";
<< ", pages " << pages << ", uses_mipmaps = " << uses_mipmaps << "\n";
}
} else {
GLCAT.debug()
<< "updating image data of texture " << tex->get_name()
<< ", " << width << " x " << height << " x " << depth
<< ", z = " << z << ", mipmaps " << num_ram_mipmap_levels
<< ", pages " << pages << ", mipmaps " << num_ram_mipmap_levels
<< ", uses_mipmaps = " << uses_mipmaps << "\n";
}
}
for (int n = mipmap_bias; n < num_levels; ++n) {
SparseArray pages = gtc->get_image_modified_pages(n);
// we grab the mipmap pointer first, if it is NULL we grab the normal
// mipmap image pointer which is a PTA_uchar
const unsigned char *image_ptr = (unsigned char*)tex->get_ram_mipmap_pointer(n);
@ -13684,8 +13631,17 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
// function.
vector_uchar clear_data = tex->get_clear_data();
_glClearTexImage(gtc->_index, n - mipmap_bias, external_format,
component_type, (void *)&clear_data[0]);
if (pages.has_all_of(0, depth)) {
_glClearTexImage(gtc->_index, n - mipmap_bias, external_format,
component_type, (void *)&clear_data[0]);
}
else for (size_t sri = 0; sri < pages.get_num_subranges(); ++sri) {
int begin = pages.get_subrange_begin(sri);
int num_pages = pages.get_subrange_end(sri) - begin;
_glClearTexSubImage(gtc->_index, n - mipmap_bias, 0, 0, begin,
width, height, num_pages, external_format,
component_type, (void *)&clear_data[0]);
}
continue;
}
} else {
@ -13714,14 +13670,11 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
}
PTA_uchar bgr_image;
size_t view_size = tex->get_ram_mipmap_view_size(n);
size_t page_size = tex->get_ram_mipmap_page_size(n);
if (image_ptr != nullptr) {
const unsigned char *orig_image_ptr = image_ptr;
size_t view_size = tex->get_ram_mipmap_view_size(n);
image_ptr += view_size * gtc->get_view();
if (one_page_only) {
view_size = tex->get_ram_mipmap_page_size(n);
image_ptr += view_size * z;
}
nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false);
if (image_compression == Texture::CM_off) {
@ -13734,23 +13687,29 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
int width = tex->get_expected_mipmap_x_size(n);
int height = tex->get_expected_mipmap_y_size(n);
#ifndef OPENGLES_1
int depth = tex->get_expected_mipmap_z_size(n);
#endif
#ifdef DO_PSTATS
_data_transferred_pcollector.add_level(view_size);
_data_transferred_pcollector.add_level(page_size * pages.get_num_on_bits());
#endif
switch (texture_target) {
#ifndef OPENGLES_1
case GL_TEXTURE_3D:
if (_supports_3d_texture) {
if (image_compression == Texture::CM_off) {
_glTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth,
external_format, component_type, image_ptr);
} else {
_glCompressedTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth,
external_format, view_size, image_ptr);
for (size_t sri = 0; sri < pages.get_num_subranges(); ++sri) {
int begin = pages.get_subrange_begin(sri);
int num_pages = pages.get_subrange_end(sri) - begin;
const unsigned char *page_ptr = image_ptr + page_size * begin;
if (image_compression == Texture::CM_off) {
_glTexSubImage3D(texture_target, n - mipmap_bias,
0, 0, begin, width, height, num_pages,
external_format, component_type, page_ptr);
} else {
_glCompressedTexSubImage3D(texture_target, n - mipmap_bias,
0, 0, begin, width, height, num_pages,
external_format,
page_size * num_pages, page_ptr);
}
}
} else {
report_my_gl_errors();
@ -13762,11 +13721,11 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
#ifndef OPENGLES
case GL_TEXTURE_1D:
if (image_compression == Texture::CM_off) {
glTexSubImage1D(page_target, n - mipmap_bias, 0, width,
glTexSubImage1D(texture_target, n - mipmap_bias, 0, width,
external_format, component_type, image_ptr);
} else {
_glCompressedTexSubImage1D(page_target, n - mipmap_bias, 0, width,
external_format, view_size, image_ptr);
_glCompressedTexSubImage1D(texture_target, n - mipmap_bias, 0, width,
external_format, page_size, image_ptr);
}
break;
#endif // OPENGLES
@ -13775,12 +13734,21 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
case GL_TEXTURE_2D_ARRAY:
case GL_TEXTURE_CUBE_MAP_ARRAY:
if (_supports_2d_texture_array) {
if (image_compression == Texture::CM_off) {
_glTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth,
external_format, component_type, image_ptr);
} else {
_glCompressedTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth,
external_format, view_size, image_ptr);
for (size_t sri = 0; sri < pages.get_num_subranges(); ++sri) {
int begin = pages.get_subrange_begin(sri);
int num_pages = pages.get_subrange_end(sri) - begin;
const unsigned char *page_ptr = image_ptr + page_size * begin;
if (image_compression == Texture::CM_off) {
_glTexSubImage3D(texture_target, n - mipmap_bias,
0, 0, begin, width, height, num_pages,
external_format, component_type, page_ptr);
} else {
_glCompressedTexSubImage3D(texture_target, n - mipmap_bias,
0, 0, begin, width, height, num_pages,
external_format,
page_size * num_pages, page_ptr);
}
}
} else {
report_my_gl_errors();
@ -13792,7 +13760,7 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
#ifndef OPENGLES
case GL_TEXTURE_BUFFER:
if (_supports_buffer_texture) {
_glBufferSubData(GL_TEXTURE_BUFFER, 0, view_size, image_ptr);
_glBufferSubData(GL_TEXTURE_BUFFER, 0, page_size, image_ptr);
} else {
report_my_gl_errors();
return false;
@ -13800,18 +13768,46 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
break;
#endif // OPENGLES
case GL_TEXTURE_CUBE_MAP:
if (_supports_cube_map) {
// This is the only texture type that must be specified using separate
// per-page calls.
if (n == 0) {
height = tex->get_y_size() - tex->get_pad_y_size();
}
for (int z = 0; z < 6; ++z) {
if (pages.get_bit(z)) {
GLenum page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z;
const unsigned char *page_ptr = image_ptr + page_size * z;
if (image_compression == Texture::CM_off) {
glTexSubImage2D(page_target, n - mipmap_bias, 0, 0, width, height,
external_format, component_type, page_ptr);
} else {
_glCompressedTexSubImage2D(page_target, n - mipmap_bias,
0, 0, width, height,
external_format, page_size, page_ptr);
}
}
}
} else {
report_my_gl_errors();
return false;
}
break;
default:
if (image_compression == Texture::CM_off) {
if (n==0) {
if (n == 0) {
// It's unfortunate that we can't adjust the width, too, but
// TexSubImage2D doesn't accept a row-stride parameter.
height = tex->get_y_size() - tex->get_pad_y_size();
}
glTexSubImage2D(page_target, n - mipmap_bias, 0, 0, width, height,
glTexSubImage2D(texture_target, n - mipmap_bias, 0, 0, width, height,
external_format, component_type, image_ptr);
} else {
_glCompressedTexSubImage2D(page_target, n - mipmap_bias, 0, 0, width, height,
external_format, view_size, image_ptr);
_glCompressedTexSubImage2D(texture_target, n - mipmap_bias, 0, 0, width, height,
external_format, page_size, image_ptr);
}
break;
}
@ -13835,7 +13831,7 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
if (GLCAT.is_debug()) {
GLCAT.debug()
<< "loading new texture object for " << tex->get_name() << ", " << width
<< " x " << height << " x " << depth << ", z = " << z << ", mipmaps "
<< " x " << height << " x " << depth << ", mipmaps "
<< num_ram_mipmap_levels << ", uses_mipmaps = " << uses_mipmaps << "\n";
}
@ -13900,10 +13896,6 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
if (image_ptr != nullptr) {
const unsigned char *orig_image_ptr = image_ptr;
image_ptr += view_size * gtc->get_view();
if (one_page_only) {
view_size = tex->get_ram_mipmap_page_size(n);
image_ptr += view_size * z;
}
nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false);
if (image_compression == Texture::CM_off) {
@ -13927,12 +13919,11 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
#ifndef OPENGLES // 1-d textures not supported by OpenGL ES. Fall through.
case GL_TEXTURE_1D:
if (image_compression == Texture::CM_off) {
glTexImage1D(page_target, n - mipmap_bias, internal_format,
width, 0,
external_format, component_type, image_ptr);
glTexImage1D(texture_target, n - mipmap_bias, internal_format,
width, 0, external_format, component_type, image_ptr);
} else {
_glCompressedTexImage1D(page_target, n - mipmap_bias, external_format, width,
0, view_size, image_ptr);
_glCompressedTexImage1D(texture_target, n - mipmap_bias, external_format,
width, 0, view_size, image_ptr);
}
break;
#endif // OPENGLES // OpenGL ES will fall through.
@ -13941,13 +13932,12 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
case GL_TEXTURE_3D:
if (_supports_3d_texture) {
if (image_compression == Texture::CM_off) {
_glTexImage3D(page_target, n - mipmap_bias, internal_format,
_glTexImage3D(texture_target, n - mipmap_bias, internal_format,
width, height, depth, 0,
external_format, component_type, image_ptr);
} else {
_glCompressedTexImage3D(page_target, n - mipmap_bias, external_format, width,
height, depth,
0, view_size, image_ptr);
_glCompressedTexImage3D(texture_target, n - mipmap_bias, external_format,
width, height, depth, 0, view_size, image_ptr);
}
} else {
report_my_gl_errors();
@ -13961,13 +13951,12 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
case GL_TEXTURE_CUBE_MAP_ARRAY:
if (_supports_2d_texture_array) {
if (image_compression == Texture::CM_off) {
_glTexImage3D(page_target, n - mipmap_bias, internal_format,
_glTexImage3D(texture_target, n - mipmap_bias, internal_format,
width, height, depth, 0,
external_format, component_type, image_ptr);
} else {
_glCompressedTexImage3D(page_target, n - mipmap_bias, external_format, width,
height, depth,
0, view_size, image_ptr);
_glCompressedTexImage3D(texture_target, n - mipmap_bias, external_format,
width, height, depth, 0, view_size, image_ptr);
}
} else {
report_my_gl_errors();
@ -13988,13 +13977,37 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
break;
#endif // OPENGLES
case GL_TEXTURE_CUBE_MAP:
if (_supports_cube_map) {
// This is the only texture type that must be specified using separate
// per-page calls.
size_t page_size = tex->get_ram_mipmap_page_size(n);
for (int z = 0; z < 6; ++z) {
GLenum page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z;
const unsigned char *page_ptr = image_ptr + page_size * z;
if (image_compression == Texture::CM_off) {
glTexImage2D(page_target, n - mipmap_bias, internal_format,
width, height, 0,
external_format, component_type, page_ptr);
} else {
_glCompressedTexImage2D(page_target, n - mipmap_bias, external_format,
width, height, 0, page_size, page_ptr);
}
}
} else {
report_my_gl_errors();
return false;
}
break;
default:
if (image_compression == Texture::CM_off) {
glTexImage2D(page_target, n - mipmap_bias, internal_format,
glTexImage2D(texture_target, n - mipmap_bias, internal_format,
width, height, 0,
external_format, component_type, image_ptr);
} else {
_glCompressedTexImage2D(page_target, n - mipmap_bias, external_format,
_glCompressedTexImage2D(texture_target, n - mipmap_bias, external_format,
width, height, 0, view_size, image_ptr);
}
}

View File

@ -616,10 +616,9 @@ protected:
bool upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps);
bool upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
bool uses_mipmaps, int mipmap_bias,
GLenum texture_target, GLenum page_target,
GLenum texture_target,
GLint internal_format, GLint external_format,
GLenum component_type,
bool one_page_only, int z,
Texture::CompressionMode image_compression);
void generate_mipmaps(CLP(TextureContext) *gtc);
bool upload_simple_texture(CLP(TextureContext) *gtc);
@ -808,6 +807,7 @@ public:
bool _supports_clear_texture;
#ifndef OPENGLES
PFNGLCLEARTEXIMAGEPROC _glClearTexImage;
PFNGLCLEARTEXSUBIMAGEPROC _glClearTexSubImage;
#endif
bool _supports_clear_buffer;

View File

@ -357,8 +357,6 @@ INLINE bool Texture::
load(const PNMImage &pnmimage, const LoaderOptions &options) {
CDWriter cdata(_cycler, true);
do_clear(cdata);
cdata->inc_properties_modified();
cdata->inc_image_modified();
if (do_load_one(cdata, pnmimage, get_name(), 0, 0, options)) {
bool generate_mipmaps = ((options.get_texture_flags() & LoaderOptions::TF_generate_mipmaps) != 0);
consider_auto_process_ram_image(generate_mipmaps || uses_mipmaps(), true);
@ -374,7 +372,7 @@ INLINE bool Texture::
load(const PNMImage &pnmimage, int z, int n, const LoaderOptions &options) {
CDWriter cdata(_cycler, true);
cdata->inc_properties_modified();
cdata->inc_image_modified();
cdata->inc_image_page_modified(z);
if (do_load_one(cdata, pnmimage, get_name(), z, n, options)) {
return true;
}
@ -388,8 +386,6 @@ INLINE bool Texture::
load(const PfmFile &pfm, const LoaderOptions &options) {
CDWriter cdata(_cycler, true);
do_clear(cdata);
cdata->inc_properties_modified();
cdata->inc_image_modified();
if (do_load_one(cdata, pfm, get_name(), 0, 0, options)) {
bool generate_mipmaps = ((options.get_texture_flags() & LoaderOptions::TF_generate_mipmaps) != 0);
consider_auto_process_ram_image(generate_mipmaps || uses_mipmaps(), true);
@ -405,7 +401,7 @@ INLINE bool Texture::
load(const PfmFile &pfm, int z, int n, const LoaderOptions &options) {
CDWriter cdata(_cycler, true);
cdata->inc_properties_modified();
cdata->inc_image_modified();
cdata->inc_image_page_modified(z);
if (do_load_one(cdata, pfm, get_name(), z, n, options)) {
return true;
}
@ -2460,11 +2456,14 @@ inc_properties_modified() {
}
/**
*
* Marks the whole image as modified.
*/
INLINE void Texture::CData::
inc_image_modified() {
++_image_modified;
_modified_pages.resize(1);
_modified_pages[0]._z_end = (size_t)-1;
_modified_pages[0]._modified = _image_modified;
}
/**

View File

@ -551,8 +551,6 @@ bool Texture::
read(const Filename &fullpath, const LoaderOptions &options) {
CDWriter cdata(_cycler, true);
do_clear(cdata);
cdata->inc_properties_modified();
cdata->inc_image_modified();
return do_read(cdata, fullpath, Filename(), 0, 0, 0, 0, false, false,
options, nullptr);
}
@ -570,8 +568,6 @@ read(const Filename &fullpath, const Filename &alpha_fullpath,
const LoaderOptions &options) {
CDWriter cdata(_cycler, true);
do_clear(cdata);
cdata->inc_properties_modified();
cdata->inc_image_modified();
return do_read(cdata, fullpath, alpha_fullpath, primary_file_num_channels,
alpha_file_channel, 0, 0, false, false,
options, nullptr);
@ -585,12 +581,15 @@ read(const Filename &fullpath, const Filename &alpha_fullpath,
* the various parameters.
*/
bool Texture::
read(const Filename &fullpath, int z, int n,
bool read_pages, bool read_mipmaps,
read(const Filename &fullpath, int z, int n, bool read_pages, bool read_mipmaps,
const LoaderOptions &options) {
CDWriter cdata(_cycler, true);
cdata->inc_properties_modified();
cdata->inc_image_modified();
if (read_pages) {
cdata->inc_image_modified();
} else {
cdata->inc_image_page_modified(z);
}
return do_read(cdata, fullpath, Filename(), 0, 0, z, n, read_pages, read_mipmaps,
options, nullptr);
}
@ -655,7 +654,11 @@ read(const Filename &fullpath, const Filename &alpha_fullpath,
const LoaderOptions &options) {
CDWriter cdata(_cycler, true);
cdata->inc_properties_modified();
cdata->inc_image_modified();
if (read_pages) {
cdata->inc_image_modified();
} else {
cdata->inc_image_page_modified(z);
}
return do_read(cdata, fullpath, alpha_fullpath, primary_file_num_channels,
alpha_file_channel, z, n, read_pages, read_mipmaps,
options, record);
@ -1422,6 +1425,39 @@ peek() {
return nullptr;
}
/**
* Returns a SparseArray containing all the image pages that have been modified
* since the given UpdateSeq value.
*/
SparseArray Texture::
get_image_modified_pages(UpdateSeq since, int n) const {
CDReader cdata(_cycler);
SparseArray result;
if (since == cdata->_image_modified) {
// Early-out since no range is more recent than _image_modified.
return result;
}
if (n > 0 && cdata->_texture_type == Texture::TT_3d_texture) {
// Don't bother handling this special case, just consider all mipmap pages
// modified.
result.set_range(0, do_get_expected_mipmap_z_size(cdata, n));
return result;
}
for (const ModifiedPageRange &range : cdata->_modified_pages) {
if (range._z_begin >= cdata->_z_size) {
break;
}
if (since < range._modified) {
result.set_range(range._z_begin, std::min(range._z_end, (size_t)cdata->_z_size) - range._z_begin);
}
}
return result;
}
/**
* Indicates that the texture should be enqueued to be prepared in the
* indicated prepared_objects at the beginning of the next frame. This will
@ -3541,7 +3577,7 @@ do_load_sub_image(CData *cdata, const PNMImage &image, int x, int y, int z, int
// Flip y
y = cdata->_y_size - (image.get_y_size() + y);
cdata->inc_image_modified();
cdata->inc_image_page_modified(z);
do_modify_ram_mipmap_image(cdata, n);
convert_from_pnmimage(cdata->_ram_images[n]._image,
do_get_expected_ram_mipmap_page_size(cdata, n),
@ -10619,6 +10655,10 @@ CData() {
_simple_ram_image._page_size = 0;
_has_clear_color = false;
_modified_pages.resize(1);
_modified_pages[0]._z_end = (size_t)-1;
_modified_pages[0]._modified = _image_modified;
}
/**
@ -10633,6 +10673,7 @@ CData(const Texture::CData &copy) {
_properties_modified = copy._properties_modified;
_image_modified = copy._image_modified;
_simple_image_modified = copy._simple_image_modified;
_modified_pages = copy._modified_pages;
}
/**
@ -10690,6 +10731,46 @@ do_assign(const Texture::CData *copy) {
_simple_ram_image = copy->_simple_ram_image;
}
/**
* Marks a single page of the image as modified.
*/
void Texture::CData::
inc_image_page_modified(int z) {
++_image_modified;
ModifiedPageRanges::iterator it = _modified_pages.begin();
while (it != _modified_pages.end() && (*it)._z_end <= z) {
++it;
continue;
}
nassertv(it != _modified_pages.end());
size_t orig_z_end = (*it)._z_end;
UpdateSeq orig_modified = (*it)._modified;
if (z > (*it)._z_begin) {
// Split prefix.
ModifiedPageRange copy(*it);
copy._z_end = z;
it = _modified_pages.insert(it, copy);
++it;
}
(*it)._z_begin = z;
(*it)._z_end = z + 1;
(*it)._modified = _image_modified;
if (z + 1 < orig_z_end) {
// Split suffix.
ModifiedPageRange copy(*it);
copy._z_begin = z + 1;
copy._z_end = orig_z_end;
copy._modified = orig_modified;
++it;
_modified_pages.insert(it, copy);
}
}
/**
* Writes the contents of this object to the datagram for shipping out to a
* Bam file.

View File

@ -525,6 +525,8 @@ PUBLISHED:
MAKE_PROPERTY(image_modified, get_image_modified);
MAKE_PROPERTY(simple_image_modified, get_simple_image_modified);
SparseArray get_image_modified_pages(UpdateSeq since, int n = 0) const;
INLINE bool has_auto_texture_scale() const;
INLINE AutoTextureScale get_auto_texture_scale() const;
INLINE void set_auto_texture_scale(AutoTextureScale scale);
@ -932,6 +934,13 @@ private:
protected:
typedef pvector<RamImage> RamImages;
struct ModifiedPageRange {
size_t _z_begin = 0;
size_t _z_end;
UpdateSeq _modified;
};
typedef pvector<ModifiedPageRange> ModifiedPageRanges;
// This is the data that must be cycled between pipeline stages.
class EXPCL_PANDA_GOBJ CData : public CycleData {
public:
@ -949,6 +958,7 @@ protected:
void do_assign(const CData *copy);
INLINE void inc_properties_modified();
INLINE void inc_image_modified();
void inc_image_page_modified(int z);
INLINE void inc_simple_image_modified();
Filename _filename;
@ -1020,6 +1030,8 @@ protected:
UpdateSeq _image_modified;
UpdateSeq _simple_image_modified;
ModifiedPageRanges _modified_pages;
public:
static TypeHandle get_class_type() {
return _type_handle;

View File

@ -76,6 +76,15 @@ was_simple_image_modified() const {
return _simple_image_modified != get_texture()->get_simple_image_modified();
}
/**
* Returns true if the given page of the texture image has been modified since
* the last time mark_loaded() was called.
*/
INLINE bool TextureContext::
was_image_page_modified(int z, int n) const {
return get_texture()->get_image_modified_pages(_image_modified, n).get_bit(z);
}
/**
* Returns a sequence number which is guaranteed to change at least every time
* the texture properties (unrelated to the image) are modified.
@ -103,6 +112,15 @@ get_simple_image_modified() const {
return _simple_image_modified;
}
/**
* Returns a SparseArray indicating which pages of the texture have been
* modified since the last call to mark_loaded().
*/
INLINE SparseArray TextureContext::
get_image_modified_pages(int n) const {
return get_texture()->get_image_modified_pages(_image_modified, n);
}
/**
* Should be called (usually by a derived class) when the on-card size of this
* object has changed.

View File

@ -44,11 +44,14 @@ PUBLISHED:
INLINE bool was_properties_modified() const;
INLINE bool was_image_modified() const;
INLINE bool was_simple_image_modified() const;
INLINE bool was_image_page_modified(int z, int n) const;
INLINE UpdateSeq get_properties_modified() const;
INLINE UpdateSeq get_image_modified() const;
INLINE UpdateSeq get_simple_image_modified() const;
INLINE SparseArray get_image_modified_pages(int n = 0) const;
public:
INLINE void update_data_size_bytes(size_t new_data_size_bytes);
INLINE void mark_loaded();

View File

@ -34,6 +34,14 @@ __reduce__(PyObject *self) const {
return result;
}
/**
*
*/
INLINE_LINMATH FLOATNAME(LMatrix3) Extension<FLOATNAME(LMatrix3)>::
__rmul__(FLOATTYPE scalar) const {
return *_this * scalar;
}
/**
*
*/

View File

@ -19,6 +19,9 @@ template<>
class Extension<FLOATNAME(LMatrix3)> : public ExtensionBase<FLOATNAME(LMatrix3)> {
public:
INLINE_LINMATH PyObject *__reduce__(PyObject *self) const;
INLINE_LINMATH FLOATNAME(LMatrix3) __rmul__(FLOATTYPE scalar) const;
INLINE_LINMATH std::string __repr__() const;
};

View File

@ -183,6 +183,8 @@ PUBLISHED:
INLINE_LINMATH FLOATNAME(LMatrix3) &operator *= (FLOATTYPE scalar);
INLINE_LINMATH FLOATNAME(LMatrix3) &operator /= (FLOATTYPE scalar);
EXTENSION(INLINE_LINMATH FLOATNAME(LMatrix3) __rmul__(FLOATTYPE scalar) const);
INLINE_LINMATH void componentwise_mult(const FLOATNAME(LMatrix3) &other);
INLINE_LINMATH FLOATTYPE determinant() const;

View File

@ -35,6 +35,14 @@ __reduce__(PyObject *self) const {
return result;
}
/**
*
*/
INLINE_LINMATH FLOATNAME(LMatrix4) Extension<FLOATNAME(LMatrix4)>::
__rmul__(FLOATTYPE scalar) const {
return *_this * scalar;
}
/**
*
*/

View File

@ -19,6 +19,9 @@ template<>
class Extension<FLOATNAME(LMatrix4)> : public ExtensionBase<FLOATNAME(LMatrix4)> {
public:
INLINE_LINMATH PyObject *__reduce__(PyObject *self) const;
INLINE_LINMATH FLOATNAME(LMatrix4) __rmul__(FLOATTYPE scalar) const;
INLINE_LINMATH std::string __repr__() const;
};

View File

@ -189,6 +189,8 @@ PUBLISHED:
INLINE_LINMATH FLOATNAME(LMatrix4) &operator *= (FLOATTYPE scalar);
INLINE_LINMATH FLOATNAME(LMatrix4) &operator /= (FLOATTYPE scalar);
EXTENSION(INLINE_LINMATH FLOATNAME(LMatrix4) __rmul__(FLOATTYPE scalar) const);
INLINE_LINMATH void componentwise_mult(const FLOATNAME(LMatrix4) &other);
INLINE_LINMATH void transpose_from(const FLOATNAME(LMatrix4) &other);

View File

@ -79,3 +79,11 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
// Upcall to LVecBase2.
return invoke_extension<FLOATNAME(LVecBase2)>(_this).__setattr__(self, attr_name, assign);
}
/**
*
*/
INLINE_LINMATH FLOATNAME(LPoint2) Extension<FLOATNAME(LPoint2)>::
__rmul__(FLOATTYPE scalar) const {
return *_this * scalar;
}

View File

@ -20,6 +20,9 @@ class Extension<FLOATNAME(LPoint2)> : public ExtensionBase<FLOATNAME(LPoint2)> {
public:
INLINE_LINMATH PyObject *__getattr__(PyObject *self, const std::string &attr_name) const;
INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
INLINE_LINMATH FLOATNAME(LPoint2) __rmul__(FLOATTYPE scalar) const;
INLINE_LINMATH std::string __repr__() const;
};

View File

@ -46,6 +46,8 @@ PUBLISHED:
INLINE_LINMATH FLOATNAME(LPoint2) operator * (FLOATTYPE scalar) const;
INLINE_LINMATH FLOATNAME(LPoint2) operator / (FLOATTYPE scalar) const;
EXTENSION(INLINE_LINMATH FLOATNAME(LPoint2) __rmul__(FLOATTYPE scalar) const);
#ifndef FLOATTYPE_IS_INT
INLINE_LINMATH FLOATNAME(LPoint2) normalized() const;
INLINE_LINMATH FLOATNAME(LPoint2) project(const FLOATNAME(LVecBase2) &onto) const;

View File

@ -80,3 +80,11 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
// Upcall to LVecBase2.
return invoke_extension<FLOATNAME(LVecBase3)>(_this).__setattr__(self, attr_name, assign);
}
/**
*
*/
INLINE_LINMATH FLOATNAME(LPoint3) Extension<FLOATNAME(LPoint3)>::
__rmul__(FLOATTYPE scalar) const {
return *_this * scalar;
}

View File

@ -20,6 +20,9 @@ class Extension<FLOATNAME(LPoint3)> : public ExtensionBase<FLOATNAME(LPoint3)> {
public:
INLINE_LINMATH PyObject *__getattr__(PyObject *self, const std::string &attr_name) const;
INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
INLINE_LINMATH FLOATNAME(LPoint3) __rmul__(FLOATTYPE scalar) const;
INLINE_LINMATH std::string __repr__() const;
};

View File

@ -66,6 +66,8 @@ PUBLISHED:
INLINE_LINMATH FLOATNAME(LPoint3) operator * (FLOATTYPE scalar) const;
INLINE_LINMATH FLOATNAME(LPoint3) operator / (FLOATTYPE scalar) const;
EXTENSION(INLINE_LINMATH FLOATNAME(LPoint3) __rmul__(FLOATTYPE scalar) const);
// Some special named constructors for LPoint3.
INLINE_LINMATH static const FLOATNAME(LPoint3) &origin(CoordinateSystem cs = CS_default);

View File

@ -85,3 +85,11 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
// Upcall to LVecBase4.
return invoke_extension<FLOATNAME(LVecBase4)>(_this).__setattr__(self, attr_name, assign);
}
/**
*
*/
INLINE_LINMATH FLOATNAME(LPoint4) Extension<FLOATNAME(LPoint4)>::
__rmul__(FLOATTYPE scalar) const {
return *_this * scalar;
}

View File

@ -20,6 +20,9 @@ class Extension<FLOATNAME(LPoint4)> : public ExtensionBase<FLOATNAME(LPoint4)> {
public:
INLINE_LINMATH PyObject *__getattr__(PyObject *self, const std::string &attr_name) const;
INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
INLINE_LINMATH FLOATNAME(LPoint4) __rmul__(FLOATTYPE scalar) const;
INLINE_LINMATH std::string __repr__() const;
};

View File

@ -54,6 +54,8 @@ PUBLISHED:
INLINE_LINMATH FLOATNAME(LPoint4) operator * (FLOATTYPE scalar) const;
INLINE_LINMATH FLOATNAME(LPoint4) operator / (FLOATTYPE scalar) const;
EXTENSION(INLINE_LINMATH FLOATNAME(LPoint4) __rmul__(FLOATTYPE scalar) const);
#ifndef FLOATTYPE_IS_INT
INLINE_LINMATH FLOATNAME(LPoint4) normalized() const;
INLINE_LINMATH FLOATNAME(LPoint4) project(const FLOATNAME(LVecBase4) &onto) const;

View File

@ -192,6 +192,25 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
return 0;
}
/**
*
*/
INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase2)>::
__rmul__(PyObject *self, FLOATTYPE scalar) const {
#ifndef CPPPARSER
extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase2);
#endif
PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
if (py_vec != nullptr) {
FLOATNAME(LVecBase2) *vec = (FLOATNAME(LVecBase2) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase2));
nassertr(vec != nullptr, nullptr);
vec->_v(0) = _this->_v(0) * scalar;
vec->_v(1) = _this->_v(1) * scalar;
}
return py_vec;
}
/**
*
*/

View File

@ -23,6 +23,8 @@ public:
INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
INLINE_LINMATH std::string __repr__() const;
INLINE_LINMATH PyObject *__rmul__(PyObject *self, FLOATTYPE scalar) const;
INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const;
INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar);

View File

@ -133,6 +133,8 @@ PUBLISHED:
INLINE_LINMATH void componentwise_mult(const FLOATNAME(LVecBase2) &other);
EXTENSION(INLINE_LINMATH PyObject *__rmul__(PyObject *self, FLOATTYPE scalar) const);
EXTENSION(INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const);
EXTENSION(INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar));

View File

@ -193,6 +193,27 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
return 0;
}
/**
*
*/
INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase3)>::
__rmul__(PyObject *self, FLOATTYPE scalar) const {
#ifndef CPPPARSER
extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase3);
#endif
PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
if (py_vec != nullptr) {
FLOATNAME(LVecBase3) *vec = (FLOATNAME(LVecBase3) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase3));
nassertr(vec != nullptr, nullptr);
vec->_v(0) = _this->_v(0) * scalar;
vec->_v(1) = _this->_v(1) * scalar;
vec->_v(2) = _this->_v(2) * scalar;
}
return py_vec;
}
/**
*
*/

View File

@ -23,6 +23,8 @@ public:
INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
INLINE_LINMATH std::string __repr__() const;
INLINE_LINMATH PyObject *__rmul__(PyObject *self, FLOATTYPE scalar) const;
INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const;
INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar);

View File

@ -152,6 +152,8 @@ PUBLISHED:
INLINE_LINMATH void componentwise_mult(const FLOATNAME(LVecBase3) &other);
EXTENSION(INLINE_LINMATH PyObject *__rmul__(PyObject *self, FLOATTYPE scalar) const);
EXTENSION(INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const);
EXTENSION(INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar));

View File

@ -199,6 +199,28 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
return 0;
}
/**
*
*/
INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase4)>::
__rmul__(PyObject *self, FLOATTYPE scalar) const {
#ifndef CPPPARSER
extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase4);
#endif
PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
if (py_vec != nullptr) {
FLOATNAME(LVecBase4) *vec = (FLOATNAME(LVecBase4) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase4));
nassertr(vec != nullptr, nullptr);
vec->_v(0) = _this->_v(0) * scalar;
vec->_v(1) = _this->_v(1) * scalar;
vec->_v(2) = _this->_v(2) * scalar;
vec->_v(3) = _this->_v(3) * scalar;
}
return py_vec;
}
/**
*
*/

View File

@ -23,6 +23,8 @@ public:
INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
INLINE_LINMATH std::string __repr__() const;
INLINE_LINMATH PyObject *__rmul__(PyObject *self, FLOATTYPE scalar) const;
INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const;
INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar);

View File

@ -160,6 +160,8 @@ PUBLISHED:
INLINE_LINMATH void componentwise_mult(const FLOATNAME(LVecBase4) &other);
EXTENSION(INLINE_LINMATH PyObject *__rmul__(PyObject *self, FLOATTYPE scalar) const);
EXTENSION(INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const);
EXTENSION(INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar));

View File

@ -79,3 +79,11 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
// Upcall to LVecBase2.
return invoke_extension<FLOATNAME(LVecBase2)>(_this).__setattr__(self, attr_name, assign);
}
/**
*
*/
INLINE_LINMATH FLOATNAME(LVector2) Extension<FLOATNAME(LVector2)>::
__rmul__(FLOATTYPE scalar) const {
return *_this * scalar;
}

View File

@ -20,6 +20,9 @@ class Extension<FLOATNAME(LVector2)> : public ExtensionBase<FLOATNAME(LVector2)>
public:
INLINE_LINMATH PyObject *__getattr__(PyObject *self, const std::string &attr_name) const;
INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
INLINE_LINMATH FLOATNAME(LVector2) __rmul__(FLOATTYPE scalar) const;
INLINE_LINMATH std::string __repr__() const;
};

View File

@ -40,6 +40,8 @@ PUBLISHED:
INLINE_LINMATH FLOATNAME(LVector2) operator * (FLOATTYPE scalar) const;
INLINE_LINMATH FLOATNAME(LVector2) operator / (FLOATTYPE scalar) const;
EXTENSION(INLINE_LINMATH FLOATNAME(LVector2) __rmul__(FLOATTYPE scalar) const);
#ifndef FLOATTYPE_IS_INT
INLINE_LINMATH FLOATNAME(LVector2) normalized() const;
INLINE_LINMATH FLOATNAME(LVector2) project(const FLOATNAME(LVecBase2) &onto) const;

View File

@ -80,3 +80,11 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
// Upcall to LVecBase3.
return invoke_extension<FLOATNAME(LVecBase3)>(_this).__setattr__(self, attr_name, assign);
}
/**
*
*/
INLINE_LINMATH FLOATNAME(LVector3) Extension<FLOATNAME(LVector3)>::
__rmul__(FLOATTYPE scalar) const {
return *_this * scalar;
}

View File

@ -20,6 +20,9 @@ class Extension<FLOATNAME(LVector3)> : public ExtensionBase<FLOATNAME(LVector3)>
public:
INLINE_LINMATH PyObject *__getattr__(PyObject *self, const std::string &attr_name) const;
INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
INLINE_LINMATH FLOATNAME(LVector3) __rmul__(FLOATTYPE scalar) const;
INLINE_LINMATH std::string __repr__() const;
};

View File

@ -71,6 +71,8 @@ PUBLISHED:
INLINE_LINMATH FLOATNAME(LVector3) operator * (FLOATTYPE scalar) const;
INLINE_LINMATH FLOATNAME(LVector3) operator / (FLOATTYPE scalar) const;
EXTENSION(INLINE_LINMATH FLOATNAME(LVector3) __rmul__(FLOATTYPE scalar) const);
// Some special named constructors for LVector3.
INLINE_LINMATH static FLOATNAME(LVector3) up(CoordinateSystem cs = CS_default);

View File

@ -85,3 +85,11 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
// Upcall to LVecBase4.
return invoke_extension<FLOATNAME(LVecBase4)>(_this).__setattr__(self, attr_name, assign);
}
/**
*
*/
INLINE_LINMATH FLOATNAME(LVector4) Extension<FLOATNAME(LVector4)>::
__rmul__(FLOATTYPE scalar) const {
return *_this * scalar;
}

View File

@ -20,6 +20,9 @@ class Extension<FLOATNAME(LVector4)> : public ExtensionBase<FLOATNAME(LVector4)>
public:
INLINE_LINMATH PyObject *__getattr__(PyObject *self, const std::string &attr_name) const;
INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
INLINE_LINMATH FLOATNAME(LVector4) __rmul__(FLOATTYPE scalar) const;
INLINE_LINMATH std::string __repr__() const;
};

View File

@ -48,6 +48,8 @@ PUBLISHED:
INLINE_LINMATH FLOATNAME(LVector4) operator * (FLOATTYPE scalar) const;
INLINE_LINMATH FLOATNAME(LVector4) operator / (FLOATTYPE scalar) const;
EXTENSION(INLINE_LINMATH FLOATNAME(LVector4) __rmul__(FLOATTYPE scalar) const);
#ifndef FLOATTYPE_IS_INT
INLINE_LINMATH FLOATNAME(LVector4) normalized() const;
INLINE_LINMATH FLOATNAME(LVector4) project(const FLOATNAME(LVecBase4) &onto) const;

View File

@ -746,6 +746,14 @@ get_num_unused_states() {
for (size_t si = 0; si < size; ++si) {
const RenderState *state = _states.get_key(si);
std::pair<StateCount::iterator, bool> ir =
state_count.insert(StateCount::value_type(state, 1));
if (!ir.second) {
// If the above insert operation fails, then it's already in the
// cache; increment its value.
(*(ir.first)).second++;
}
size_t i;
size_t cache_size = state->_composition_cache.get_num_entries();
for (i = 0; i < cache_size; ++i) {
@ -1843,6 +1851,7 @@ init_states() {
// is declared globally, and lives forever.
RenderState *state = new RenderState;
state->local_object();
state->cache_ref_only();
state->_saved_entry = _states.store(state, nullptr);
_empty_state = state;
}

View File

@ -145,6 +145,7 @@ PUBLISHED:
static void list_states(std::ostream &out);
static bool validate_states();
EXTENSION(static PyObject *get_states());
EXTENSION(static PyObject *get_unused_states());
PUBLISHED:
// These methods are intended for use by low-level code, but they're also

View File

@ -139,4 +139,29 @@ get_states() {
return list;
}
/**
* Returns a list of all of the "unused" RenderState objects in the state
* cache. See get_num_unused_states().
*/
PyObject *Extension<RenderState>::
get_unused_states() {
extern struct Dtool_PyTypedObject Dtool_RenderState;
LightReMutexHolder holder(*RenderState::_states_lock);
PyObject *list = PyList_New(0);
size_t size = RenderState::_states.get_num_entries();
for (size_t si = 0; si < size; ++si) {
const RenderState *state = RenderState::_states.get_key(si);
if (state->get_cache_ref_count() == state->get_ref_count()) {
state->ref();
PyObject *a =
DTool_CreatePyInstanceTyped((void *)state, Dtool_RenderState,
true, true, state->get_type_index());
PyList_Append(list, a);
Py_DECREF(a);
}
}
return list;
}
#endif // HAVE_PYTHON

View File

@ -32,6 +32,7 @@ public:
PyObject *get_composition_cache() const;
PyObject *get_invert_composition_cache() const;
static PyObject *get_states();
static PyObject *get_unused_states();
};
#endif // HAVE_PYTHON

View File

@ -1017,6 +1017,14 @@ get_num_unused_states() {
for (size_t si = 0; si < size; ++si) {
const TransformState *state = _states.get_key(si);
std::pair<StateCount::iterator, bool> ir =
state_count.insert(StateCount::value_type(state, 1));
if (!ir.second) {
// If the above insert operation fails, then it's already in the
// cache; increment its value.
(*(ir.first)).second++;
}
size_t i;
size_t cache_size = state->_composition_cache.get_num_entries();
for (i = 0; i < cache_size; ++i) {

View File

@ -41,7 +41,8 @@ PGEntry::
PGEntry(const string &name) :
PGItem(name),
_text(get_text_node()),
_obscure_text(get_text_node())
_obscure_text(get_text_node()),
_candidate_text(get_text_node())
{
set_cull_callback();
@ -103,6 +104,7 @@ PGEntry(const PGEntry &copy) :
PGItem(copy),
_text(copy._text),
_obscure_text(copy._obscure_text),
_candidate_text(copy._candidate_text),
_cursor_position(copy._cursor_position),
_cursor_visible(copy._cursor_visible),
_candidate_highlight_start(copy._candidate_highlight_start),
@ -216,11 +218,6 @@ press(const MouseWatcherParameter &param, bool background) {
} else if ((!background && get_focus()) ||
(background && get_background_focus())) {
// Keyboard button.
if (!_candidate_wtext.empty()) {
_candidate_wtext = wstring();
_text_geom_stale = true;
}
_cursor_position = min(_cursor_position, _text.get_num_characters());
_blink_start = ClockObject::get_global_clock()->get_frame_time();
if (button == KeyboardButton::enter()) {
@ -797,9 +794,16 @@ update_text() {
} else {
TextPropertiesManager *tp_mgr = TextPropertiesManager::get_global_ptr();
bool has_inactive = tp_mgr->has_properties(_candidate_inactive);
TextProperties inactive = tp_mgr->get_properties(_candidate_inactive);
TextProperties active = tp_mgr->get_properties(_candidate_active);
if (!has_inactive) {
// Just underscoring the candidate is a sensible default.
inactive.set_underscore(true);
tp_mgr->set_properties(_candidate_inactive, inactive);
}
// Insert the complex sequence of characters required to show the
// candidate string in a different color. This gets inserted at the
// current cursor position.
@ -818,9 +822,9 @@ update_text() {
cseq += wstring(1, (wchar_t)text_pop_properties_key);
// Create a special TextAssembler to insert the candidate string.
TextAssembler ctext(_text);
ctext.set_wsubstr(cseq, _cursor_position, 0);
assembled = ctext.assemble_text();
_candidate_text = _text;
_candidate_text.set_wsubstr(cseq, _cursor_position, 0);
assembled = _candidate_text.assemble_text();
}
if (!_current_text.is_empty()) {
@ -902,7 +906,8 @@ update_cursor() {
_obscure_text.calc_r_c(row, column, _cursor_position);
xpos = _obscure_text.get_xpos(row, column);
ypos = _obscure_text.get_ypos(row, column);
} else {
}
else if (_candidate_wtext.empty()) {
_text.calc_r_c(row, column, _cursor_position);
if (_cursor_position > 0 && _text.get_character(_cursor_position - 1) == '\n') {
row += 1;
@ -911,6 +916,11 @@ update_cursor() {
xpos = _text.get_xpos(row, column);
ypos = _text.get_ypos(row, column);
}
else {
_candidate_text.calc_r_c(row, column, _cursor_position + (int)_candidate_cursor_pos);
xpos = _candidate_text.get_xpos(row, column);
ypos = _candidate_text.get_ypos(row, column);
}
_cursor_def.set_pos(xpos - _current_padding, 0.0f, ypos);
_cursor_stale = false;
@ -919,7 +929,7 @@ update_cursor() {
}
// Should the cursor be visible?
if (!get_focus() || !_candidate_wtext.empty()) {
if (!get_focus()) {
show_hide_cursor(false);
} else {
double elapsed_time =

View File

@ -149,6 +149,7 @@ private:
TextAssembler _text;
TextAssembler _obscure_text;
TextAssembler _candidate_text;
int _cursor_position;
bool _cursor_stale;
bool _cursor_visible;

View File

@ -215,21 +215,28 @@ has_bits_in_common(const SparseArray &other) const {
*/
void SparseArray::
output(std::ostream &out) const {
if (_subranges.empty()) {
out << (_inverse ? "[ all ]" : "[ ]");
return;
}
out << "[ ";
if (_inverse) {
out << "all except: ";
}
Subranges::const_iterator si;
for (si = _subranges.begin(); si != _subranges.end(); ++si) {
if (si != _subranges.begin()) {
out << ", ";
}
if ((*si)._end == (*si)._begin + 1) {
// A single element.
out << (*si)._begin << ", ";
out << (*si)._begin;
} else {
// A range of elements.
out << (*si)._begin << "-" << ((*si)._end - 1) << ", ";
out << (*si)._begin << "-" << ((*si)._end - 1);
}
}
out << "]";
out << " ]";
}
/**

View File

@ -49,12 +49,6 @@ ConfigVariableBool auto_cpu_data
"require an explicit call to pipe->lookup_cpu_data(). Setting this "
"true may slow down startup time by 1-2 seconds."));
ConfigVariableBool ime_aware
("ime-aware", false,
PRC_DESC("Set this true to show ime texts on the chat panel and hide the "
"IME default windows. This is a mechanism to work around DX8/9 "
"interface."));
ConfigVariableBool ime_hide
("ime-hide", false,
PRC_DESC("Set this true to hide ime windows."));

View File

@ -25,8 +25,6 @@ extern ConfigVariableBool responsive_minimized_fullscreen_window;
extern ConfigVariableBool hold_keys_across_windows;
extern ConfigVariableBool do_vidmemsize_check;
extern ConfigVariableBool auto_cpu_data;
extern ConfigVariableBool ime_composition_w;
extern ConfigVariableBool ime_aware;
extern ConfigVariableBool ime_hide;
extern ConfigVariableBool request_dxdisplay_information;
extern ConfigVariableBool dpi_aware;

View File

@ -493,7 +493,8 @@ process_events() {
break;
case ClientMessage:
if ((Atom)(event.xclient.data.l[0]) == _wm_delete_window) {
if ((Atom)(event.xclient.data.l[0]) == _wm_delete_window &&
event.xany.window == _xwindow) {
// This is a message from the window manager indicating that the user
// has requested to close the window.
string close_request_event = get_close_request_event();
@ -860,12 +861,15 @@ set_properties_now(WindowProperties &properties) {
int value_mask = 0;
if (_properties.get_fullscreen()) {
changes.x = 0;
changes.y = 0;
value_mask |= CWX | CWY;
properties.clear_origin();
} else if (properties.has_origin()) {
if (_properties.get_x_origin() != 0 ||
_properties.get_y_origin() != 0) {
changes.x = 0;
changes.y = 0;
value_mask |= CWX | CWY;
properties.clear_origin();
}
}
else if (properties.has_origin()) {
changes.x = properties.get_x_origin();
changes.y = properties.get_y_origin();
if (changes.x != -1) value_mask |= CWX;
@ -1049,22 +1053,6 @@ set_properties_now(WindowProperties &properties) {
}
}
/**
* Overridden from GraphicsWindow.
*/
void x11GraphicsWindow::
mouse_mode_absolute() {
// unused: remove in 1.10!
}
/**
* Overridden from GraphicsWindow.
*/
void x11GraphicsWindow::
mouse_mode_relative() {
// unused: remove in 1.10!
}
/**
* Closes the window right now. Called from the window thread.
*/
@ -1195,15 +1183,41 @@ open_window() {
set_wm_properties(_properties, false);
// We don't specify any fancy properties of the XIC. It would be nicer if
// we could support fancy IM's that want preedit callbacks, etc., but that
// can wait until we have an X server that actually supports these to test
// it on.
// Initialize the input context, which (if enabled) will enable us to capture
// candidate strings and display them inside Panda3D rather than via an
// external popup window.
XIM im = x11_pipe->get_im();
_ic = nullptr;
if (im) {
_ic = XCreateIC(im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, _xwindow, nullptr);
if (ime_aware) {
XIMCallback start_callback;
start_callback.client_data = (XPointer)this;
start_callback.callback = (XIMProc)xim_preedit_start;
XIMCallback draw_callback;
draw_callback.client_data = (XPointer)this;
draw_callback.callback = (XIMProc)xim_preedit_draw;
XIMCallback caret_callback;
caret_callback.client_data = (XPointer)this;
caret_callback.callback = (XIMProc)xim_preedit_caret;
XIMCallback done_callback;
done_callback.client_data = (XPointer)this;
done_callback.callback = (XIMProc)xim_preedit_done;
XVaNestedList preedit_attributes = XVaCreateNestedList(
0,
XNPreeditStartCallback, &start_callback,
XNPreeditDrawCallback, &draw_callback,
XNPreeditCaretCallback, &caret_callback,
XNPreeditDoneCallback, &done_callback,
nullptr);
_ic = XCreateIC(im,
XNInputStyle, XIMPreeditCallbacks | XIMStatusNothing,
XNClientWindow, _xwindow,
XNPreeditAttributes, preedit_attributes,
nullptr);
} else {
_ic = XCreateIC(im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, _xwindow, nullptr);
}
if (_ic == (XIC)nullptr) {
x11display_cat.warning()
<< "Couldn't create input context.\n";
@ -1562,6 +1576,123 @@ open_raw_mice() {
#endif
}
/**
*
*/
int x11GraphicsWindow::
handle_preedit_start() {
_preedit_state = new PreeditState;
if (x11display_cat.is_spam()) {
x11display_cat.spam()
<< "Preedit started\n";
}
return sizeof(_preedit_state->_buffer) / sizeof(wchar_t);
}
/**
*
*/
void x11GraphicsWindow::
handle_preedit_draw(XIMPreeditDrawCallbackStruct &data) {
nassertv_always(_preedit_state != nullptr);
PreeditState &state = *_preedit_state;
if (data.text != nullptr) {
// Replace characters in the preedit buffer.
int added_chars = data.text->length - data.chg_length;
memmove(state._buffer + data.chg_first,
state._buffer + data.chg_first + data.chg_length,
state._length - (size_t)(data.chg_first + data.chg_length) + data.text->length);
state._length += added_chars;
if (added_chars != 0) {
if (state._highlight_start > data.chg_first) {
state._highlight_start = std::max(data.chg_first, state._highlight_start + added_chars);
}
if (state._highlight_end > data.chg_first) {
state._highlight_end = std::max(data.chg_first, state._highlight_end + added_chars);
}
}
if (data.text->encoding_is_wchar) {
memcpy(state._buffer + data.chg_first, data.text->string.wide_char, data.text->length * sizeof(wchar_t));
} else {
mbstowcs(state._buffer + data.chg_first, data.text->string.multi_byte, data.text->length);
}
if (data.text->feedback != nullptr) {
// Update the highlighted region.
for (int i = 0; i < data.text->length; ++i) {
if (data.text->feedback[i] & XIMReverse) {
if (state._highlight_end > state._highlight_start) {
state._highlight_start = std::min(state._highlight_start, data.chg_first + i);
state._highlight_end = std::max(state._highlight_end, data.chg_first + i + 1);
} else {
state._highlight_start = data.chg_first + i;
state._highlight_end = data.chg_first + i + 1;
}
}
else if (state._highlight_end > state._highlight_start) {
if (state._highlight_start == data.chg_first + i) {
++state._highlight_start;
}
if (state._highlight_end == data.chg_first + i + 1) {
--state._highlight_end;
}
if (state._highlight_end <= state._highlight_start) {
state._highlight_start = 0;
state._highlight_end = 0;
}
}
}
}
} else {
// Delete characters from the preedit buffer.
memmove(state._buffer + data.chg_first,
state._buffer + data.chg_first + data.chg_length,
state._length - (size_t)(data.chg_first + data.chg_length));
state._length -= data.chg_length;
if (state._highlight_start > data.chg_first) {
state._highlight_start = std::max(data.chg_first, state._highlight_start - data.chg_length);
}
if (state._highlight_end > data.chg_first) {
state._highlight_end = std::max(data.chg_first, state._highlight_end - data.chg_length);
}
}
_input->candidate(std::wstring(state._buffer, state._length),
state._highlight_start, state._highlight_end, data.caret);
}
/**
*
*/
void x11GraphicsWindow::
handle_preedit_caret(XIMPreeditCaretCallbackStruct &data) {
nassertv_always(_preedit_state != nullptr);
PreeditState &state = *_preedit_state;
if (data.direction == XIMAbsolutePosition) {
_input->candidate(std::wstring(state._buffer, state._length),
state._highlight_start, state._highlight_end, data.position);
}
}
/**
*
*/
void x11GraphicsWindow::
handle_preedit_done() {
if (x11display_cat.is_spam()) {
x11display_cat.spam()
<< "Preedit done\n";
}
delete _preedit_state;
_preedit_state = nullptr;
}
/**
* Generates a keystroke corresponding to the indicated X KeyPress event.
*/
@ -2207,7 +2338,8 @@ check_event(X11_Display *display, XEvent *event, char *arg) {
// We accept any event that is sent to our window. However, we have to let
// raw mouse events through, since they're not associated with any window.
return (event->xany.window == self->_xwindow ||
(event->type == GenericEvent && self->_raw_mouse_enabled));
(event->type == GenericEvent && self->_raw_mouse_enabled)) ||
(event->type == ClientMessage);
}
/**
@ -2523,3 +2655,43 @@ cleanup:
return ret;
}
/**
*
*/
int x11GraphicsWindow::
xim_preedit_start(XIC ic, XPointer client_data, XPointer call_data) {
x11GraphicsWindow *window = (x11GraphicsWindow *)client_data;
return window->handle_preedit_start();
}
/**
*
*/
void x11GraphicsWindow::
xim_preedit_draw(XIC ic, XPointer client_data,
XIMPreeditDrawCallbackStruct *call_data) {
x11GraphicsWindow *window = (x11GraphicsWindow *)client_data;
nassertv_always(call_data != nullptr);
window->handle_preedit_draw(*call_data);
}
/**
*
*/
void x11GraphicsWindow::
xim_preedit_caret(XIC ic, XPointer client_data,
XIMPreeditCaretCallbackStruct *call_data) {
x11GraphicsWindow *window = (x11GraphicsWindow *)client_data;
nassertv_always(call_data != nullptr);
window->handle_preedit_caret(*call_data);
}
/**
*
*/
void x11GraphicsWindow::
xim_preedit_done(XIC ic, XPointer client_data, XPointer call_data) {
x11GraphicsWindow *window = (x11GraphicsWindow *)client_data;
window->handle_preedit_done();
}

View File

@ -50,13 +50,14 @@ protected:
virtual void close_window();
virtual bool open_window();
virtual void mouse_mode_absolute();
virtual void mouse_mode_relative();
void set_wm_properties(const WindowProperties &properties,
bool already_mapped);
virtual void setup_colormap(XVisualInfo *visual);
int handle_preedit_start();
void handle_preedit_draw(XIMPreeditDrawCallbackStruct &data);
void handle_preedit_caret(XIMPreeditCaretCallbackStruct &data);
void handle_preedit_done();
void handle_keystroke(XKeyEvent &event);
void handle_keypress(XKeyEvent &event);
void handle_keyrelease(XKeyEvent &event);
@ -75,6 +76,11 @@ private:
X11_Cursor get_cursor(const Filename &filename);
X11_Cursor read_ico(std::istream &ico);
static int xim_preedit_start(XIC ic, XPointer client_data, XPointer call_data);
static void xim_preedit_draw(XIC ic, XPointer client_data, XIMPreeditDrawCallbackStruct *call_data);
static void xim_preedit_caret(XIC ic, XPointer client_data, XIMPreeditCaretCallbackStruct *call_data);
static void xim_preedit_done(XIC ic, XPointer client_data, XPointer call_data);
protected:
X11_Display *_display;
int _screen;
@ -88,6 +94,13 @@ protected:
LVecBase2i _fixed_size;
GraphicsWindowInputDevice *_input;
struct PreeditState {
wchar_t _buffer[1024];
size_t _length = 0;
int _highlight_start = 0;
int _highlight_end = 0;
};
PreeditState *_preedit_state = nullptr;
long _event_mask;
bool _awaiting_configure;

View File

@ -619,7 +619,7 @@ load_mesh(size_t index) {
PT(GeomVertexArrayFormat) aformat = new GeomVertexArrayFormat;
aformat->add_column(InternalName::get_vertex(), 3, Geom::NT_stdfloat, Geom::C_point);
if (mesh.HasNormals()) {
aformat->add_column(InternalName::get_normal(), 3, Geom::NT_stdfloat, Geom::C_vector);
aformat->add_column(InternalName::get_normal(), 3, Geom::NT_stdfloat, Geom::C_normal);
}
if (mesh.HasVertexColors(0)) {
aformat->add_column(InternalName::get_color(), 4, Geom::NT_stdfloat, Geom::C_color);

View File

@ -120,6 +120,10 @@ def test_vec2_ceil():
assert rounded_vector.y == -2
def test_vec2_rmul():
assert 2 * Vec2(3, -4) == Vec2(6, -8)
@pytest.mark.parametrize("type", (core.LVecBase2f, core.LVecBase2d, core.LVecBase2i))
def test_vec2_floordiv(type):
with pytest.raises(ZeroDivisionError):

View File

@ -105,6 +105,10 @@ def test_vec3_ceil():
assert rounded_vector.z == 4
def test_vec3_rmul():
assert 2 * Vec3(0, 3, -4) == Vec3(0, 6, -8)
@pytest.mark.parametrize("type", (core.LVecBase3f, core.LVecBase3d, core.LVecBase3i))
def test_vec3_floordiv(type):
with pytest.raises(ZeroDivisionError):

View File

@ -121,6 +121,10 @@ def test_vec4_ceil():
assert rounded_vector.w == 1
def test_vec4_rmul():
assert 2 * Vec4(0, 3, -4, 0.5) == Vec4(0, 6, -8, 1)
@pytest.mark.parametrize("type", (core.LVecBase4f, core.LVecBase4d, core.LVecBase4i))
def test_vec4_floordiv(type):
with pytest.raises(ZeroDivisionError):