Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
fe157b00af
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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."));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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 ©) {
|
|||
_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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -34,6 +34,14 @@ __reduce__(PyObject *self) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE_LINMATH FLOATNAME(LMatrix3) Extension<FLOATNAME(LMatrix3)>::
|
||||
__rmul__(FLOATTYPE scalar) const {
|
||||
return *_this * scalar;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,14 @@ __reduce__(PyObject *self) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE_LINMATH FLOATNAME(LMatrix4) Extension<FLOATNAME(LMatrix4)>::
|
||||
__rmul__(FLOATTYPE scalar) const {
|
||||
return *_this * scalar;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 ©) :
|
|||
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 ¶m, 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 =
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ private:
|
|||
|
||||
TextAssembler _text;
|
||||
TextAssembler _obscure_text;
|
||||
TextAssembler _candidate_text;
|
||||
int _cursor_position;
|
||||
bool _cursor_stale;
|
||||
bool _cursor_visible;
|
||||
|
|
|
|||
|
|
@ -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 << " ]";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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."));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Loading…
Reference in New Issue