Browse Source

Merge branch 'release/1.10.x'

rdb 2 years ago
parent
commit
b282e8920d

+ 1 - 1
README.md

@@ -24,7 +24,7 @@ Installing Panda3D
 ==================
 ==================
 
 
 The latest Panda3D SDK can be downloaded from
 The latest Panda3D SDK can be downloaded from
-[this page](https://www.panda3d.org/download/sdk-1-10-12/).
+[this page](https://www.panda3d.org/download/sdk-1-10-13/).
 If you are familiar with installing Python packages, you can use
 If you are familiar with installing Python packages, you can use
 the following command:
 the following command:
 
 

+ 64 - 55
panda/src/cocoadisplay/cocoaGraphicsWindow.mm

@@ -814,7 +814,12 @@ set_properties_now(WindowProperties &properties) {
           if (switched) {
           if (switched) {
             if (_window != nil) {
             if (_window != nil) {
               // For some reason, setting the style mask makes it give up its
               // For some reason, setting the style mask makes it give up its
-              // first-responder status.
+              // first-responder status.  And for some reason, we need to first
+              // restore the window to normal level before we switch fullscreen,
+              // otherwise we may get a black bar if we're currently on Z_top.
+              if (_properties.get_z_order() != WindowProperties::Z_normal) {
+                [_window setLevel: NSNormalWindowLevel];
+              }
               if ([_window respondsToSelector:@selector(setStyleMask:)]) {
               if ([_window respondsToSelector:@selector(setStyleMask:)]) {
                 [_window setStyleMask:NSBorderlessWindowMask];
                 [_window setStyleMask:NSBorderlessWindowMask];
               }
               }
@@ -847,8 +852,12 @@ set_properties_now(WindowProperties &properties) {
         _properties.set_fullscreen(false);
         _properties.set_fullscreen(false);
 
 
         // Force properties to be reset to their actual values
         // Force properties to be reset to their actual values
-        properties.set_undecorated(_properties.get_undecorated());
-        properties.set_z_order(_properties.get_z_order());
+        if (!properties.has_undecorated()) {
+          properties.set_undecorated(_properties.get_undecorated());
+        }
+        if (!properties.has_z_order()) {
+          properties.set_z_order(_properties.get_z_order());
+        }
         properties.clear_fullscreen();
         properties.clear_fullscreen();
       }
       }
     }
     }
@@ -865,6 +874,58 @@ set_properties_now(WindowProperties &properties) {
     properties.clear_minimized();
     properties.clear_minimized();
   }
   }
 
 
+  if (properties.has_title() && _window != nil) {
+    _properties.set_title(properties.get_title());
+    [_window setTitle:[NSString stringWithUTF8String:properties.get_title().c_str()]];
+    properties.clear_title();
+  }
+
+  if (properties.has_fixed_size() && _window != nil) {
+    _properties.set_fixed_size(properties.get_fixed_size());
+    [_window setShowsResizeIndicator:!properties.get_fixed_size()];
+
+    if (!_properties.get_fullscreen()) {
+      // If our window is decorated, change the style mask to show or hide the
+      // resize button appropriately.  However, if we're specifying the
+      // 'undecorated' property also, then we'll be setting the style mask
+      // about 25 LOC further down, so we won't need to bother setting it
+      // here.
+      if (!properties.has_undecorated() && !_properties.get_undecorated() &&
+          [_window respondsToSelector:@selector(setStyleMask:)]) {
+        if (properties.get_fixed_size()) {
+          [_window setStyleMask:NSTitledWindowMask | NSClosableWindowMask |
+                                NSMiniaturizableWindowMask ];
+        } else {
+          [_window setStyleMask:NSTitledWindowMask | NSClosableWindowMask |
+                                NSMiniaturizableWindowMask | NSResizableWindowMask ];
+        }
+        [_window makeFirstResponder:_view];
+      }
+    }
+
+    properties.clear_fixed_size();
+  }
+
+  if (properties.has_undecorated() && _window != nil && [_window respondsToSelector:@selector(setStyleMask:)]) {
+    _properties.set_undecorated(properties.get_undecorated());
+
+    if (!_properties.get_fullscreen()) {
+      if (properties.get_undecorated()) {
+        [_window setStyleMask: NSBorderlessWindowMask];
+      } else if (_properties.get_fixed_size()) {
+        // Fixed size windows should not show the resize button.
+        [_window setStyleMask: NSTitledWindowMask | NSClosableWindowMask |
+                               NSMiniaturizableWindowMask ];
+      } else {
+        [_window setStyleMask: NSTitledWindowMask | NSClosableWindowMask |
+                               NSMiniaturizableWindowMask | NSResizableWindowMask ];
+      }
+      [_window makeFirstResponder:_view];
+    }
+
+    properties.clear_undecorated();
+  }
+
   if (properties.has_size()) {
   if (properties.has_size()) {
     int width = properties.get_x_size();
     int width = properties.get_x_size();
     int height = properties.get_y_size();
     int height = properties.get_y_size();
@@ -978,58 +1039,6 @@ set_properties_now(WindowProperties &properties) {
     properties.clear_maximized();
     properties.clear_maximized();
   }
   }
 
 
-  if (properties.has_title() && _window != nil) {
-    _properties.set_title(properties.get_title());
-    [_window setTitle:[NSString stringWithUTF8String:properties.get_title().c_str()]];
-    properties.clear_title();
-  }
-
-  if (properties.has_fixed_size() && _window != nil) {
-    _properties.set_fixed_size(properties.get_fixed_size());
-    [_window setShowsResizeIndicator:!properties.get_fixed_size()];
-
-    if (!_properties.get_fullscreen()) {
-      // If our window is decorated, change the style mask to show or hide the
-      // resize button appropriately.  However, if we're specifying the
-      // 'undecorated' property also, then we'll be setting the style mask
-      // about 25 LOC further down, so we won't need to bother setting it
-      // here.
-      if (!properties.has_undecorated() && !_properties.get_undecorated() &&
-          [_window respondsToSelector:@selector(setStyleMask:)]) {
-        if (properties.get_fixed_size()) {
-          [_window setStyleMask:NSTitledWindowMask | NSClosableWindowMask |
-                                NSMiniaturizableWindowMask ];
-        } else {
-          [_window setStyleMask:NSTitledWindowMask | NSClosableWindowMask |
-                                NSMiniaturizableWindowMask | NSResizableWindowMask ];
-        }
-        [_window makeFirstResponder:_view];
-      }
-    }
-
-    properties.clear_fixed_size();
-  }
-
-  if (properties.has_undecorated() && _window != nil && [_window respondsToSelector:@selector(setStyleMask:)]) {
-    _properties.set_undecorated(properties.get_undecorated());
-
-    if (!_properties.get_fullscreen()) {
-      if (properties.get_undecorated()) {
-        [_window setStyleMask: NSBorderlessWindowMask];
-      } else if (_properties.get_fixed_size()) {
-        // Fixed size windows should not show the resize button.
-        [_window setStyleMask: NSTitledWindowMask | NSClosableWindowMask |
-                               NSMiniaturizableWindowMask ];
-      } else {
-        [_window setStyleMask: NSTitledWindowMask | NSClosableWindowMask |
-                               NSMiniaturizableWindowMask | NSResizableWindowMask ];
-      }
-      [_window makeFirstResponder:_view];
-    }
-
-    properties.clear_undecorated();
-  }
-
   if (properties.has_foreground() && !_properties.get_fullscreen() && _window != nil) {
   if (properties.has_foreground() && !_properties.get_fullscreen() && _window != nil) {
     _properties.set_foreground(properties.get_foreground());
     _properties.set_foreground(properties.get_foreground());
     if (!_properties.get_minimized()) {
     if (!_properties.get_minimized()) {

+ 47 - 0
panda/src/display/graphicsStateGuardian.cxx

@@ -57,6 +57,7 @@
 #include "colorScaleAttrib.h"
 #include "colorScaleAttrib.h"
 #include "clipPlaneAttrib.h"
 #include "clipPlaneAttrib.h"
 #include "fogAttrib.h"
 #include "fogAttrib.h"
+#include "renderModeAttrib.h"
 #include "config_pstatclient.h"
 #include "config_pstatclient.h"
 
 
 #include <limits.h>
 #include <limits.h>
@@ -1267,6 +1268,25 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
     }
     }
     return;
     return;
   }
   }
+  case Shader::SMO_texconst_i: {
+    const TexGenAttrib *tga;
+    const TextureAttrib *ta;
+
+    int num_stages = 0;
+    if (_target_rs->get_attrib(ta) && _target_rs->get_attrib(tga)) {
+      num_stages = std::min(count, (int)ta->get_num_on_stages());
+    }
+
+    int i = 0;
+    for (; i < num_stages; ++i) {
+      LVecBase3 value = tga->get_constant_value(ta->get_on_stage(i));
+      into[i].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, value[0], value[1], value[2], 1);
+    }
+    for (; i < count; ++i) {
+      into[i] = LMatrix4::ident_mat();
+    }
+    return;
+  }
   case Shader::SMO_tex_is_alpha_i: {
   case Shader::SMO_tex_is_alpha_i: {
     // This is a hack so we can support both F_alpha and other formats in the
     // This is a hack so we can support both F_alpha and other formats in the
     // default shader, to fix font rendering in GLES2
     // default shader, to fix font rendering in GLES2
@@ -1628,6 +1648,33 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
     }
     }
     return;
     return;
   }
   }
+  case Shader::SMO_attr_pointparams: {
+    const RenderModeAttrib *target_render_mode;
+    _target_rs->get_attrib_def(target_render_mode);
+
+    PN_stdfloat thickness = target_render_mode->get_thickness();
+    PN_stdfloat catten = thickness;
+    PN_stdfloat patten = 0.0f;
+    if (target_render_mode->get_perspective()) {
+      LVecBase2i pixel_size = _current_display_region->get_pixel_size();
+
+      LVector3 height(0.0f, thickness, 1.0f);
+      height = height * _projection_mat->get_mat();
+      height = height * _internal_transform->get_scale()[1];
+      PN_stdfloat s = height[1] * pixel_size[1];
+
+      if (_current_lens->is_orthographic()) {
+        catten = s;
+        patten = 0.0f;
+      } else {
+        catten = 0.0f;
+        patten = s;
+      }
+    }
+
+    into[0].set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, thickness, catten, patten, 0.0f);
+    return;
+  }
   default:
   default:
     nassertv(false /*should never get here*/);
     nassertv(false /*should never get here*/);
     return;
     return;

+ 10 - 10
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -3149,6 +3149,7 @@ set_state_and_transform(const RenderState *target,
   }
   }
   _target_rs = target;
   _target_rs = target;
 
 
+  int shader_deps = 0;
   determine_target_shader();
   determine_target_shader();
 
 
   int alpha_test_slot = AlphaTestAttrib::get_class_slot();
   int alpha_test_slot = AlphaTestAttrib::get_class_slot();
@@ -3178,10 +3179,7 @@ set_state_and_transform(const RenderState *target,
     do_issue_color_scale();
     do_issue_color_scale();
     _state_mask.set_bit(color_slot);
     _state_mask.set_bit(color_slot);
     _state_mask.set_bit(color_scale_slot);
     _state_mask.set_bit(color_scale_slot);
-    if (_current_shader_context) {
-      _current_shader_context->issue_parameters(this, Shader::SSD_color);
-      _current_shader_context->issue_parameters(this, Shader::SSD_colorscale);
-    }
+    shader_deps |= Shader::SSD_color | Shader::SSD_colorscale;
   }
   }
 
 
   int cull_face_slot = CullFaceAttrib::get_class_slot();
   int cull_face_slot = CullFaceAttrib::get_class_slot();
@@ -3222,6 +3220,7 @@ set_state_and_transform(const RenderState *target,
     // PStatTimer timer(_draw_set_state_render_mode_pcollector);
     // PStatTimer timer(_draw_set_state_render_mode_pcollector);
     do_issue_render_mode();
     do_issue_render_mode();
     _state_mask.set_bit(render_mode_slot);
     _state_mask.set_bit(render_mode_slot);
+    shader_deps |= Shader::SSD_render_mode;
   }
   }
 
 
   int rescale_normal_slot = RescaleNormalAttrib::get_class_slot();
   int rescale_normal_slot = RescaleNormalAttrib::get_class_slot();
@@ -3285,6 +3284,7 @@ set_state_and_transform(const RenderState *target,
     _state_mask.set_bit(texture_slot);
     _state_mask.set_bit(texture_slot);
     _state_mask.set_bit(tex_matrix_slot);
     _state_mask.set_bit(tex_matrix_slot);
     _state_mask.set_bit(tex_gen_slot);
     _state_mask.set_bit(tex_gen_slot);
+    shader_deps |= Shader::SSD_tex_matrix | Shader::SSD_tex_gen;
   }
   }
 
 
   int material_slot = MaterialAttrib::get_class_slot();
   int material_slot = MaterialAttrib::get_class_slot();
@@ -3293,9 +3293,7 @@ set_state_and_transform(const RenderState *target,
     // PStatTimer timer(_draw_set_state_material_pcollector);
     // PStatTimer timer(_draw_set_state_material_pcollector);
     do_issue_material();
     do_issue_material();
     _state_mask.set_bit(material_slot);
     _state_mask.set_bit(material_slot);
-    if (_current_shader_context) {
-      _current_shader_context->issue_parameters(this, Shader::SSD_material);
-    }
+    shader_deps |= Shader::SSD_material;
   }
   }
 
 
   int light_slot = LightAttrib::get_class_slot();
   int light_slot = LightAttrib::get_class_slot();
@@ -3320,9 +3318,7 @@ set_state_and_transform(const RenderState *target,
     // PStatTimer timer(_draw_set_state_fog_pcollector);
     // PStatTimer timer(_draw_set_state_fog_pcollector);
     do_issue_fog();
     do_issue_fog();
     _state_mask.set_bit(fog_slot);
     _state_mask.set_bit(fog_slot);
-    if (_current_shader_context) {
-      _current_shader_context->issue_parameters(this, Shader::SSD_fog);
-    }
+    shader_deps |= Shader::SSD_fog;
   }
   }
 
 
   int scissor_slot = ScissorAttrib::get_class_slot();
   int scissor_slot = ScissorAttrib::get_class_slot();
@@ -3333,6 +3329,10 @@ set_state_and_transform(const RenderState *target,
     _state_mask.set_bit(scissor_slot);
     _state_mask.set_bit(scissor_slot);
   }
   }
 
 
+  if (_current_shader_context != nullptr && shader_deps != 0) {
+    _current_shader_context->issue_parameters(this, shader_deps);
+  }
+
   _state_rs = _target_rs;
   _state_rs = _target_rs;
 }
 }
 
 

+ 28 - 0
panda/src/dxgsg9/dxShaderContext9.cxx

@@ -254,6 +254,7 @@ issue_parameters(GSG *gsg, int altered) {
           HRESULT hr;
           HRESULT hr;
           PN_stdfloat v [4];
           PN_stdfloat v [4];
           LMatrix4f temp_matrix = LCAST(float, *val);
           LMatrix4f temp_matrix = LCAST(float, *val);
+          LMatrix3f temp_matrix3;
 
 
           hr = D3D_OK;
           hr = D3D_OK;
 
 
@@ -315,6 +316,33 @@ issue_parameters(GSG *gsg, int altered) {
             hr = cgD3D9SetUniform(p, v);
             hr = cgD3D9SetUniform(p, v);
             break;
             break;
 
 
+          case Shader::SMP_upper3x3:
+            // TRANSPOSE REQUIRED
+            temp_matrix3 = temp_matrix.get_upper_3();
+            temp_matrix3.transpose_in_place();
+            data = temp_matrix3.get_data();
+
+            hr = cgD3D9SetUniform(p, data);
+            break;
+
+          case Shader::SMP_transpose3x3:
+            // NO TRANSPOSE REQUIRED
+            temp_matrix3 = temp_matrix.get_upper_3();
+            data = temp_matrix3.get_data();
+
+            hr = cgD3D9SetUniform(p, data);
+            break;
+
+          case Shader::SMP_cell15:
+            hr = cgD3D9SetUniform(p, data + 15);
+            continue;
+          case Shader::SMP_cell14:
+            hr = cgD3D9SetUniform(p, data + 14);
+            continue;
+          case Shader::SMP_cell13:
+            hr = cgD3D9SetUniform(p, data + 13);
+            continue;
+
           default:
           default:
             dxgsg9_cat.error()
             dxgsg9_cat.error()
               << "issue_parameters () SMP parameter type not implemented " << spec._piece << "\n";
               << "issue_parameters () SMP parameter type not implemented " << spec._piece << "\n";

+ 8 - 0
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -486,6 +486,14 @@ set_state_and_transform(const RenderState *target_rs,
         target_rs->get_attrib(TexMatrixAttrib::get_class_slot())) {
         target_rs->get_attrib(TexMatrixAttrib::get_class_slot())) {
       altered |= Shader::SSD_tex_matrix;
       altered |= Shader::SSD_tex_matrix;
     }
     }
+    if (state_rs->get_attrib(TexGenAttrib::get_class_slot()) !=
+        target_rs->get_attrib(TexGenAttrib::get_class_slot())) {
+      altered |= Shader::SSD_tex_gen;
+    }
+    if (state_rs->get_attrib(RenderModeAttrib::get_class_slot()) !=
+        target_rs->get_attrib(RenderModeAttrib::get_class_slot())) {
+      altered |= Shader::SSD_render_mode;
+    }
     _state_rs = target_rs;
     _state_rs = target_rs;
   }
   }
 
 

+ 28 - 14
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -12340,6 +12340,8 @@ set_state_and_transform(const RenderState *target,
   }
   }
 
 
   int texture_slot = TextureAttrib::get_class_slot();
   int texture_slot = TextureAttrib::get_class_slot();
+  int tex_gen_slot = TexGenAttrib::get_class_slot();
+  int tex_matrix_slot = TexMatrixAttrib::get_class_slot();
   if (_target_rs->get_attrib(texture_slot) != _state_rs->get_attrib(texture_slot) ||
   if (_target_rs->get_attrib(texture_slot) != _state_rs->get_attrib(texture_slot) ||
       !_state_mask.get_bit(texture_slot)) {
       !_state_mask.get_bit(texture_slot)) {
     //PStatGPUTimer timer(this, _draw_set_state_texture_pcollector);
     //PStatGPUTimer timer(this, _draw_set_state_texture_pcollector);
@@ -12355,7 +12357,7 @@ set_state_and_transform(const RenderState *target,
       _target_texture = (const TextureAttrib *)
       _target_texture = (const TextureAttrib *)
         _target_rs->get_attrib_def(TextureAttrib::get_class_slot());
         _target_rs->get_attrib_def(TextureAttrib::get_class_slot());
       _target_tex_gen = (const TexGenAttrib *)
       _target_tex_gen = (const TexGenAttrib *)
-        _target_rs->get_attrib_def(TexGenAttrib::get_class_slot());
+        _target_rs->get_attrib_def(tex_gen_slot);
     }
     }
 #endif
 #endif
     do_issue_texture();
     do_issue_texture();
@@ -12363,28 +12365,36 @@ set_state_and_transform(const RenderState *target,
     // Since the TexGen and TexMatrix states depend partly on the particular
     // Since the TexGen and TexMatrix states depend partly on the particular
     // set of textures in use, we should force both of those to be reissued
     // set of textures in use, we should force both of those to be reissued
     // every time we change the texture state.
     // every time we change the texture state.
-    _state_mask.clear_bit(TexGenAttrib::get_class_slot());
-    _state_mask.clear_bit(TexMatrixAttrib::get_class_slot());
+    _state_mask.clear_bit(tex_gen_slot);
+    _state_mask.clear_bit(tex_matrix_slot);
 
 
     _state_texture = _target_texture;
     _state_texture = _target_texture;
     _state_mask.set_bit(texture_slot);
     _state_mask.set_bit(texture_slot);
   }
   }
+  else if (_target_rs->get_attrib(tex_gen_slot) != _state_rs->get_attrib(tex_gen_slot) ||
+           !_state_mask.get_bit(tex_gen_slot)) {
+    _target_tex_gen = (const TexGenAttrib *)_target_rs->get_attrib_def(tex_gen_slot);
+
+#ifdef SUPPORT_FIXED_FUNCTION
+#ifdef OPENGLES_1
+    if (_has_texture_alpha_scale) {
+#else
+    if (_has_texture_alpha_scale && _current_shader == nullptr) {
+#endif
+      PT(TextureStage) stage = get_alpha_scale_texture_stage();
+      _target_tex_gen = DCAST(TexGenAttrib, _target_tex_gen->add_stage
+                              (stage, TexGenAttrib::M_constant, LTexCoord3(_current_color_scale[3], 0.0f, 0.0f)));
+    }
+#endif  // SUPPORT_FIXED_FUNCTION
 
 
-  // If one of the previously-loaded TexGen modes modified the texture matrix,
-  // then if either state changed, we have to change both of them now.
-  if (_tex_gen_modifies_mat) {
-    int tex_gen_slot = TexGenAttrib::get_class_slot();
-    int tex_matrix_slot = TexMatrixAttrib::get_class_slot();
-    if (_target_rs->get_attrib(tex_gen_slot) != _state_rs->get_attrib(tex_gen_slot) ||
-        _target_rs->get_attrib(tex_matrix_slot) != _state_rs->get_attrib(tex_matrix_slot) ||
-        !_state_mask.get_bit(tex_gen_slot) ||
-        !_state_mask.get_bit(tex_matrix_slot)) {
+    // If one of the previously-loaded TexGen modes modified the texture matrix,
+    // then if either state changed, we have to change both of them now.
+    if (_tex_gen_modifies_mat) {
       _state_mask.clear_bit(tex_gen_slot);
       _state_mask.clear_bit(tex_gen_slot);
       _state_mask.clear_bit(tex_matrix_slot);
       _state_mask.clear_bit(tex_matrix_slot);
     }
     }
   }
   }
 
 
-  int tex_matrix_slot = TexMatrixAttrib::get_class_slot();
   if (_target_rs->get_attrib(tex_matrix_slot) != _state_rs->get_attrib(tex_matrix_slot) ||
   if (_target_rs->get_attrib(tex_matrix_slot) != _state_rs->get_attrib(tex_matrix_slot) ||
       !_state_mask.get_bit(tex_matrix_slot)) {
       !_state_mask.get_bit(tex_matrix_slot)) {
     // PStatGPUTimer timer(this, _draw_set_state_tex_matrix_pcollector);
     // PStatGPUTimer timer(this, _draw_set_state_tex_matrix_pcollector);
@@ -12399,11 +12409,15 @@ set_state_and_transform(const RenderState *target,
       _current_shader_context->issue_parameters(Shader::SSD_tex_matrix);
       _current_shader_context->issue_parameters(Shader::SSD_tex_matrix);
     }
     }
 #endif
 #endif
+
+    // See previous occurrence of this check.
+    if (_tex_gen_modifies_mat) {
+      _state_mask.clear_bit(tex_gen_slot);
+    }
   }
   }
 
 
 #ifdef SUPPORT_FIXED_FUNCTION
 #ifdef SUPPORT_FIXED_FUNCTION
   if (has_fixed_function_pipeline()) {
   if (has_fixed_function_pipeline()) {
-    int tex_gen_slot = TexGenAttrib::get_class_slot();
     if (_target_tex_gen != _state_tex_gen ||
     if (_target_tex_gen != _state_tex_gen ||
         !_state_mask.get_bit(tex_gen_slot)) {
         !_state_mask.get_bit(tex_gen_slot)) {
       // PStatGPUTimer timer(this, _draw_set_state_tex_gen_pcollector);
       // PStatGPUTimer timer(this, _draw_set_state_tex_gen_pcollector);

+ 9 - 0
panda/src/glstuff/glShaderContext_src.cxx

@@ -25,6 +25,7 @@
 #include "fogAttrib.h"
 #include "fogAttrib.h"
 #include "lightAttrib.h"
 #include "lightAttrib.h"
 #include "clipPlaneAttrib.h"
 #include "clipPlaneAttrib.h"
+#include "renderModeAttrib.h"
 #include "bamCache.h"
 #include "bamCache.h"
 
 
 using std::dec;
 using std::dec;
@@ -2078,6 +2079,14 @@ set_state_and_transform(const RenderState *target_rs,
         target_rs->get_attrib(TextureAttrib::get_class_slot())) {
         target_rs->get_attrib(TextureAttrib::get_class_slot())) {
       altered |= Shader::SSD_texture;
       altered |= Shader::SSD_texture;
     }
     }
+    if (state_rs->get_attrib(TexGenAttrib::get_class_slot()) !=
+        target_rs->get_attrib(TexGenAttrib::get_class_slot())) {
+      altered |= Shader::SSD_tex_gen;
+    }
+    if (state_rs->get_attrib(RenderModeAttrib::get_class_slot()) !=
+        target_rs->get_attrib(RenderModeAttrib::get_class_slot())) {
+      altered |= Shader::SSD_render_mode;
+    }
     _state_rs = target_rs;
     _state_rs = target_rs;
   }
   }
 
 

+ 38 - 0
panda/src/gobj/shader.cxx

@@ -500,6 +500,12 @@ cp_dependency(ShaderMatInput inp) {
   if (inp == SMO_tex_is_alpha_i || inp == SMO_texcolor_i) {
   if (inp == SMO_tex_is_alpha_i || inp == SMO_texcolor_i) {
     dep |= SSD_texture | SSD_frame;
     dep |= SSD_texture | SSD_frame;
   }
   }
+  if (inp == SMO_texconst_i) {
+    dep |= SSD_tex_gen;
+  }
+  if (inp == SMO_attr_pointparams) {
+    dep |= SSD_render_mode | SSD_transform | SSD_frame;
+  }
 
 
   return dep;
   return dep;
 }
 }
@@ -1116,6 +1122,17 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
       bind._part[1] = SMO_identity;
       bind._part[1] = SMO_identity;
       bind._arg[1] = nullptr;
       bind._arg[1] = nullptr;
       bind._index = atoi(pieces[1].c_str() + 5);
       bind._index = atoi(pieces[1].c_str() + 5);
+    } else if (pieces[1] == "pointparams") {
+      if (!cp_errchk_parameter_float(p,3,4)) {
+        return false;
+      }
+      bind._id = p._id;
+      bind._piece = SMP_row3;
+      bind._func = SMF_first;
+      bind._part[0] = SMO_attr_pointparams;
+      bind._arg[0] = nullptr;
+      bind._part[1] = SMO_identity;
+      bind._arg[1] = nullptr;
     } else {
     } else {
       cp_report_error(p,"Unknown attr parameter.");
       cp_report_error(p,"Unknown attr parameter.");
       return false;
       return false;
@@ -1282,6 +1299,27 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
     return true;
     return true;
   }
   }
 
 
+  if (pieces[0] == "texconst") {
+    if ((!cp_errchk_parameter_words(p,2))||
+        (!cp_errchk_parameter_in(p)) ||
+        (!cp_errchk_parameter_uniform(p))||
+        (!cp_errchk_parameter_float(p,3,4))) {
+      return false;
+    }
+    ShaderMatSpec bind;
+    bind._id = p._id;
+    bind._piece = SMP_row3;
+    bind._func = SMF_first;
+    bind._part[0] = SMO_texconst_i;
+    bind._arg[0] = nullptr;
+    bind._part[1] = SMO_identity;
+    bind._arg[1] = nullptr;
+    bind._index = atoi(pieces[1].c_str());
+
+    cp_add_mat_spec(bind);
+    return true;
+  }
+
   if (pieces[0] == "plane") {
   if (pieces[0] == "plane") {
     if ((!cp_errchk_parameter_words(p,2))||
     if ((!cp_errchk_parameter_words(p,2))||
         (!cp_errchk_parameter_in(p)) ||
         (!cp_errchk_parameter_in(p)) ||

+ 8 - 0
panda/src/gobj/shader.h

@@ -216,6 +216,12 @@ public:
     // Color of an M_blend texture stage.
     // Color of an M_blend texture stage.
     SMO_texcolor_i,
     SMO_texcolor_i,
 
 
+    // Constant value of the TexGenAttrib of stage i.
+    SMO_texconst_i,
+
+    // Point parameters
+    SMO_attr_pointparams,
+
     SMO_INVALID
     SMO_INVALID
   };
   };
 
 
@@ -323,6 +329,8 @@ public:
     SSD_projection    = 0x800,
     SSD_projection    = 0x800,
     SSD_texture      = 0x1000,
     SSD_texture      = 0x1000,
     SSD_view_transform= 0x2000,
     SSD_view_transform= 0x2000,
+    SSD_tex_gen      = 0x4000,
+    SSD_render_mode  = 0x8000,
   };
   };
 
 
   enum ShaderBug {
   enum ShaderBug {

+ 82 - 22
panda/src/pgraphnodes/shaderGenerator.cxx

@@ -38,6 +38,7 @@
 #include "texture.h"
 #include "texture.h"
 #include "ambientLight.h"
 #include "ambientLight.h"
 #include "directionalLight.h"
 #include "directionalLight.h"
+#include "renderModeAttrib.h"
 #include "rescaleNormalAttrib.h"
 #include "rescaleNormalAttrib.h"
 #include "pointLight.h"
 #include "pointLight.h"
 #include "sphereLight.h"
 #include "sphereLight.h"
@@ -567,6 +568,12 @@ analyze_renderstate(ShaderKey &key, const RenderState *rs) {
   if (rs->get_attrib(fog) && !fog->is_off()) {
   if (rs->get_attrib(fog) && !fog->is_off()) {
     key._fog_mode = (int)fog->get_fog()->get_mode() + 1;
     key._fog_mode = (int)fog->get_fog()->get_mode() + 1;
   }
   }
+
+  // Hijack this field for the perspective render-mode flag.
+  const RenderModeAttrib *render_mode;
+  if (rs->get_attrib(render_mode) && render_mode->get_perspective()) {
+    key._fog_mode |= 0x10000;
+  }
 }
 }
 
 
 /**
 /**
@@ -754,6 +761,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   bool need_eye_position = key._lighting;
   bool need_eye_position = key._lighting;
   bool need_eye_normal = !key._lights.empty() || ((key._outputs & AuxBitplaneAttrib::ABO_aux_normal) != 0);
   bool need_eye_normal = !key._lights.empty() || ((key._outputs & AuxBitplaneAttrib::ABO_aux_normal) != 0);
   bool need_tangents = ((key._texture_flags & ShaderKey::TF_map_normal) != 0);
   bool need_tangents = ((key._texture_flags & ShaderKey::TF_map_normal) != 0);
+  bool need_point_size = (key._fog_mode & 0x10000) != 0;
 
 
   // If we have binormal/tangent and eye position, we can pack eye normal in
   // If we have binormal/tangent and eye position, we can pack eye normal in
   // the w channels of the others.
   // the w channels of the others.
@@ -781,23 +789,34 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
     }
     }
   }
   }
 
 
+  bool need_eye_reflection = false;
+  bool need_fragment_view_to_world = false;
+
   text << "void vshader(\n";
   text << "void vshader(\n";
   for (size_t i = 0; i < key._textures.size(); ++i) {
   for (size_t i = 0; i < key._textures.size(); ++i) {
     const ShaderKey::TextureInfo &tex = key._textures[i];
     const ShaderKey::TextureInfo &tex = key._textures[i];
 
 
     switch (tex._gen_mode) {
     switch (tex._gen_mode) {
-    case TexGenAttrib::M_world_position:
-      need_world_position = true;
+    case TexGenAttrib::M_world_cube_map:
+      need_fragment_view_to_world = true;
+    case TexGenAttrib::M_eye_sphere_map:
+    case TexGenAttrib::M_eye_cube_map:
+      need_eye_position = true;
+      need_eye_normal = true;
+      need_eye_reflection = true;
       break;
       break;
     case TexGenAttrib::M_world_normal:
     case TexGenAttrib::M_world_normal:
       need_world_normal = true;
       need_world_normal = true;
       break;
       break;
-    case TexGenAttrib::M_eye_position:
-      need_eye_position = true;
-      break;
     case TexGenAttrib::M_eye_normal:
     case TexGenAttrib::M_eye_normal:
       need_eye_normal = true;
       need_eye_normal = true;
       break;
       break;
+    case TexGenAttrib::M_world_position:
+      need_world_position = true;
+      break;
+    case TexGenAttrib::M_eye_position:
+      need_eye_position = true;
+      break;
     default:
     default:
       break;
       break;
     }
     }
@@ -866,7 +885,8 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
     text << "\t uniform float4x4 trans_model_to_view,\n";
     text << "\t uniform float4x4 trans_model_to_view,\n";
     eye_position_freg = alloc_freg();
     eye_position_freg = alloc_freg();
     text << "\t out float4 l_eye_position : " << eye_position_freg << ",\n";
     text << "\t out float4 l_eye_position : " << eye_position_freg << ",\n";
-  } else if (need_tangents) {
+  }
+  else if (need_tangents || need_point_size) {
     text << "\t uniform float4x4 trans_model_to_view,\n";
     text << "\t uniform float4x4 trans_model_to_view,\n";
   }
   }
   if (need_eye_normal) {
   if (need_eye_normal) {
@@ -883,7 +903,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
     text << "\t uniform float4 mspos_view,\n";
     text << "\t uniform float4 mspos_view,\n";
     text << "\t out float3 l_eyevec,\n";
     text << "\t out float3 l_eyevec,\n";
   }
   }
-  if (key._fog_mode != 0) {
+  if ((key._fog_mode & 0xffff) != 0) {
     hpos_freg = alloc_freg();
     hpos_freg = alloc_freg();
     text << "\t out float4 l_hpos : " << hpos_freg << ",\n";
     text << "\t out float4 l_hpos : " << hpos_freg << ",\n";
   }
   }
@@ -923,6 +943,10 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
       text << "\t in uint4 vtx_transform_index : " << transform_index_vreg << ",\n";
       text << "\t in uint4 vtx_transform_index : " << transform_index_vreg << ",\n";
     }
     }
   }
   }
+  if (need_point_size) {
+    text << "\t uniform float3 attr_pointparams,\n";
+    text << "\t out float l_point_size : PSIZE,\n";
+  }
   text << "\t in float4 vtx_position : " << position_vreg << ",\n";
   text << "\t in float4 vtx_position : " << position_vreg << ",\n";
   text << "\t out float4 l_position : POSITION,\n";
   text << "\t out float4 l_position : POSITION,\n";
   text << "\t uniform float4x4 mat_modelproj\n";
   text << "\t uniform float4x4 mat_modelproj\n";
@@ -954,7 +978,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   }
   }
 
 
   text << "\t l_position = mul(mat_modelproj, vtx_position);\n";
   text << "\t l_position = mul(mat_modelproj, vtx_position);\n";
-  if (key._fog_mode != 0) {
+  if ((key._fog_mode & 0xffff) != 0) {
     text << "\t l_hpos = l_position;\n";
     text << "\t l_hpos = l_position;\n";
   }
   }
   if (need_world_position) {
   if (need_world_position) {
@@ -966,6 +990,13 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   if (need_eye_position) {
   if (need_eye_position) {
     text << "\t l_eye_position = mul(trans_model_to_view, vtx_position);\n";
     text << "\t l_eye_position = mul(trans_model_to_view, vtx_position);\n";
   }
   }
+  else if (need_point_size) {
+    text << "\t float4 l_eye_position = mul(trans_model_to_view, vtx_position);\n";
+  }
+  if (need_point_size) {
+    text << "\t l_point_size = attr_pointparams.y + attr_pointparams.z / length(l_eye_position.xyz);\n";
+  }
+
   pmap<const InternalName *, const char *>::const_iterator it;
   pmap<const InternalName *, const char *>::const_iterator it;
   for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
   for (it = texcoord_fregs.begin(); it != texcoord_fregs.end(); ++it) {
     // Pass through all texcoord inputs as-is.
     // Pass through all texcoord inputs as-is.
@@ -1011,7 +1042,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   // Fragment shader
   // Fragment shader
 
 
   text << "void fshader(\n";
   text << "void fshader(\n";
-  if (key._fog_mode != 0) {
+  if ((key._fog_mode & 0xffff) != 0) {
     text << "\t in float4 l_hpos : " << hpos_freg << ",\n";
     text << "\t in float4 l_hpos : " << hpos_freg << ",\n";
     text << "\t in uniform float4 attr_fog,\n";
     text << "\t in uniform float4 attr_fog,\n";
     text << "\t in uniform float4 attr_fogcolor,\n";
     text << "\t in uniform float4 attr_fogcolor,\n";
@@ -1049,6 +1080,13 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
     if (tex._flags & ShaderKey::TF_uses_color) {
     if (tex._flags & ShaderKey::TF_uses_color) {
       text << "\t uniform float4 texcolor_" << i << ",\n";
       text << "\t uniform float4 texcolor_" << i << ",\n";
     }
     }
+
+    if (tex._gen_mode == TexGenAttrib::M_constant) {
+      text << "\t uniform float4 texconst_" << i << ",\n";
+    }
+  }
+  if (need_fragment_view_to_world) {
+    text << "\t uniform float3x3 trans_view_to_world,\n";
   }
   }
   if (need_tangents) {
   if (need_tangents) {
     text << "\t in float4 l_tangent : " << tangent_freg << ",\n";
     text << "\t in float4 l_tangent : " << tangent_freg << ",\n";
@@ -1119,6 +1157,17 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   if (need_eye_normal && pack_eye_normal) {
   if (need_eye_normal && pack_eye_normal) {
     text << "\t float3 l_eye_normal = float3(l_tangent.w, l_binormal.w, l_eye_position.w);\n";
     text << "\t float3 l_eye_normal = float3(l_tangent.w, l_binormal.w, l_eye_position.w);\n";
   }
   }
+  if (need_eye_normal) {
+    text << "\t // Correct the surface normal for interpolation effects\n";
+    text << "\t l_eye_normal = normalize(l_eye_normal);\n";
+  }
+  if (need_eye_reflection ||
+      (need_eye_position && have_specular && (key._material_flags & Material::F_local) != 0 && !key._lights.empty())) {
+    text << "\t float3 norm_eye_position = normalize(l_eye_position.xyz);\n";
+  }
+  if (need_eye_reflection) {
+    text << "\t float3 eye_reflection = norm_eye_position - l_eye_normal * 2 * dot(l_eye_normal, norm_eye_position);\n";
+  }
 
 
   text << "\t float4 result;\n";
   text << "\t float4 result;\n";
   if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) {
   if (key._outputs & (AuxBitplaneAttrib::ABO_aux_normal | AuxBitplaneAttrib::ABO_aux_glow)) {
@@ -1137,17 +1186,29 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
       // Cg seems to be able to optimize this temporary away when appropriate.
       // Cg seems to be able to optimize this temporary away when appropriate.
       text << "\t float4 texcoord" << i << " = l_" << tex._texcoord_name->join("_") << ";\n";
       text << "\t float4 texcoord" << i << " = l_" << tex._texcoord_name->join("_") << ";\n";
       break;
       break;
-    case TexGenAttrib::M_world_position:
-      text << "\t float4 texcoord" << i << " = l_world_position;\n";
+    case TexGenAttrib::M_eye_sphere_map:
+      text << "\t float4 texcoord" << i << " = float4(eye_reflection.xz * (1.0f / (2.0f * length(eye_reflection + float3(0, -1, 0)))) + float2(0.5f, 0.5f), 0.0f, 1.0f);\n";
+      break;
+    case TexGenAttrib::M_world_cube_map:
+      text << "\t float4 texcoord" << i << " = float4(mul(trans_view_to_world, eye_reflection), 1.0f);\n";
+      break;
+    case TexGenAttrib::M_eye_cube_map:
+      text << "\t float4 texcoord" << i << " = float4(eye_reflection, 1.0f);\n";
       break;
       break;
     case TexGenAttrib::M_world_normal:
     case TexGenAttrib::M_world_normal:
       text << "\t float4 texcoord" << i << " = l_world_normal;\n";
       text << "\t float4 texcoord" << i << " = l_world_normal;\n";
       break;
       break;
+    case TexGenAttrib::M_eye_normal:
+      text << "\t float4 texcoord" << i << " = float4(l_eye_normal, 1.0f);\n";
+      break;
+    case TexGenAttrib::M_world_position:
+      text << "\t float4 texcoord" << i << " = l_world_position;\n";
+      break;
     case TexGenAttrib::M_eye_position:
     case TexGenAttrib::M_eye_position:
       text << "\t float4 texcoord" << i << " = float4(l_eye_position.xyz, 1.0f);\n";
       text << "\t float4 texcoord" << i << " = float4(l_eye_position.xyz, 1.0f);\n";
       break;
       break;
-    case TexGenAttrib::M_eye_normal:
-      text << "\t float4 texcoord" << i << " = float4(l_eye_normal, 1.0f);\n";
+    case TexGenAttrib::M_constant:
+      text << "\t float4 texcoord" << i << " = texconst_" << i << ";\n";
       break;
       break;
     default:
     default:
       text << "\t float4 texcoord" << i << " = float4(0, 0, 0, 0);\n";
       text << "\t float4 texcoord" << i << " = float4(0, 0, 0, 0);\n";
@@ -1240,10 +1301,6 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
       text << ");\n";
       text << ");\n";
     }
     }
   }
   }
-  if (need_eye_normal) {
-    text << "\t // Correct the surface normal for interpolation effects\n";
-    text << "\t l_eye_normal = normalize(l_eye_normal);\n";
-  }
   if (need_tangents) {
   if (need_tangents) {
     text << "\t // Translate tangent-space normal in map to view-space.\n";
     text << "\t // Translate tangent-space normal in map to view-space.\n";
 
 
@@ -1338,7 +1395,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
       text << "\t tot_diffuse += lcolor;\n";
       text << "\t tot_diffuse += lcolor;\n";
       if (have_specular) {
       if (have_specular) {
         if (key._material_flags & Material::F_local) {
         if (key._material_flags & Material::F_local) {
-          text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
+          text << "\t lhalf = normalize(lvec - norm_eye_position);\n";
         } else {
         } else {
           text << "\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
           text << "\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
         }
         }
@@ -1373,7 +1430,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
       text << "\t tot_diffuse += lcolor;\n";
       text << "\t tot_diffuse += lcolor;\n";
       if (have_specular) {
       if (have_specular) {
         if (key._material_flags & Material::F_local) {
         if (key._material_flags & Material::F_local) {
-          text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
+          text << "\t lhalf = normalize(lvec - norm_eye_position);\n";
         } else {
         } else {
           text << "\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
           text << "\t lhalf = normalize(lvec - float3(0, 1, 0));\n";
         }
         }
@@ -1413,7 +1470,7 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
       text << "\t tot_diffuse += lcolor;\n";
       text << "\t tot_diffuse += lcolor;\n";
       if (have_specular) {
       if (have_specular) {
         if (key._material_flags & Material::F_local) {
         if (key._material_flags & Material::F_local) {
-          text << "\t lhalf = normalize(lvec - normalize(l_eye_position.xyz));\n";
+          text << "\t lhalf = normalize(lvec - norm_eye_position);\n";
         } else {
         } else {
           text << "\t lhalf = normalize(lvec - float3(0,1,0));\n";
           text << "\t lhalf = normalize(lvec - float3(0,1,0));\n";
         }
         }
@@ -1683,8 +1740,8 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   }
   }
 
 
   // Apply fog.
   // Apply fog.
-  if (key._fog_mode != 0) {
-    Fog::Mode fog_mode = (Fog::Mode)(key._fog_mode - 1);
+  if ((key._fog_mode & 0xffff) != 0) {
+    Fog::Mode fog_mode = (Fog::Mode)((key._fog_mode & 0xffff) - 1);
     switch (fog_mode) {
     switch (fog_mode) {
     case Fog::M_linear:
     case Fog::M_linear:
       text << "\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate((attr_fog.z - l_hpos.z) * attr_fog.w));\n";
       text << "\t result.rgb = lerp(attr_fogcolor.rgb, result.rgb, saturate((attr_fog.z - l_hpos.z) * attr_fog.w));\n";
@@ -1729,6 +1786,9 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
   if (flags != 0) {
   if (flags != 0) {
     shattr = DCAST(ShaderAttrib, shattr)->set_flag(flags, true);
     shattr = DCAST(ShaderAttrib, shattr)->set_flag(flags, true);
   }
   }
+  if (need_point_size) {
+    shattr = DCAST(ShaderAttrib, shattr)->set_flag(ShaderAttrib::F_shader_point_size, true);
+  }
 
 
   reset_register_allocator();
   reset_register_allocator();
 
 

+ 1 - 0
panda/src/pgraphnodes/shaderGenerator.h

@@ -150,6 +150,7 @@ protected:
     bool _lighting;
     bool _lighting;
     bool _have_separate_ambient;
     bool _have_separate_ambient;
 
 
+    // Also contains bit 0x10000 indicating perspective point mode
     int _fog_mode;
     int _fog_mode;
 
 
     int _outputs;
     int _outputs;

+ 5 - 6
panda/src/x11display/x11GraphicsWindow.cxx

@@ -133,12 +133,6 @@ x11GraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
  */
  */
 x11GraphicsWindow::
 x11GraphicsWindow::
 ~x11GraphicsWindow() {
 ~x11GraphicsWindow() {
-  if (!_cursor_filenames.empty()) {
-    LightReMutexHolder holder(x11GraphicsPipe::_x_mutex);
-    for (auto item : _cursor_filenames) {
-      XFreeCursor(_display, item.second);
-    }
-  }
 }
 }
 
 
 /**
 /**
@@ -1122,6 +1116,11 @@ close_window() {
     _orig_size_id = -1;
     _orig_size_id = -1;
   }
   }
 
 
+  for (auto item : _cursor_filenames) {
+    XFreeCursor(_display, item.second);
+  }
+  _cursor_filenames.clear();
+
   GraphicsWindow::close_window();
   GraphicsWindow::close_window();
 }
 }
 
 

+ 37 - 2
pandatool/src/deploy-stub/deploy-stub.c

@@ -82,6 +82,16 @@ static struct _inittab extensions[] = {
 static wchar_t *log_pathw = NULL;
 static wchar_t *log_pathw = NULL;
 #endif
 #endif
 
 
+#if PY_VERSION_HEX >= 0x030b0000
+typedef struct {
+  const char *name;
+  const unsigned char *code;
+  int size;
+} ModuleDef;
+#else
+typedef struct _frozen ModuleDef;
+#endif
+
 /**
 /**
  * Sets the main_dir field of the blobinfo structure, but only if it wasn't
  * Sets the main_dir field of the blobinfo structure, but only if it wasn't
  * already set.
  * already set.
@@ -627,7 +637,7 @@ int wmain(int argc, wchar_t *argv[]) {
 int main(int argc, char *argv[]) {
 int main(int argc, char *argv[]) {
 #endif
 #endif
   int retval;
   int retval;
-  struct _frozen *moddef;
+  ModuleDef *moddef;
   const char *log_filename;
   const char *log_filename;
   void *blob = NULL;
   void *blob = NULL;
   log_filename = NULL;
   log_filename = NULL;
@@ -677,6 +687,9 @@ int main(int argc, char *argv[]) {
 
 
     // Offset the pointers in the module table using the base mmap address.
     // Offset the pointers in the module table using the base mmap address.
     moddef = blobinfo.pointers[0];
     moddef = blobinfo.pointers[0];
+#if PY_VERSION_HEX < 0x030b0000
+    PyImport_FrozenModules = moddef;
+#endif
     while (moddef->name) {
     while (moddef->name) {
       moddef->name = (char *)((uintptr_t)moddef->name + (uintptr_t)blob);
       moddef->name = (char *)((uintptr_t)moddef->name + (uintptr_t)blob);
       if (moddef->code != 0) {
       if (moddef->code != 0) {
@@ -685,6 +698,24 @@ int main(int argc, char *argv[]) {
       //printf("MOD: %s %p %d\n", moddef->name, (void*)moddef->code, moddef->size);
       //printf("MOD: %s %p %d\n", moddef->name, (void*)moddef->code, moddef->size);
       moddef++;
       moddef++;
     }
     }
+
+    // In Python 3.11, we need to convert this to the new structure format.
+#if PY_VERSION_HEX >= 0x030b0000
+    ModuleDef *moddef_end = moddef;
+    ptrdiff_t num_modules = moddef - (ModuleDef *)blobinfo.pointers[0];
+    struct _frozen *new_moddef = (struct _frozen *)calloc(num_modules + 1, sizeof(struct _frozen));
+    PyImport_FrozenModules = new_moddef;
+    for (moddef = blobinfo.pointers[0]; moddef < moddef_end; ++moddef) {
+      new_moddef->name = moddef->name;
+      new_moddef->code = moddef->code;
+      new_moddef->size = moddef->size < 0 ? -(moddef->size) : moddef->size;
+      new_moddef->is_package = moddef->size < 0;
+      new_moddef->get_code = NULL;
+      new_moddef++;
+    }
+#endif
+  } else {
+    PyImport_FrozenModules = blobinfo.pointers[0];
   }
   }
 
 
   if (log_filename != NULL) {
   if (log_filename != NULL) {
@@ -707,12 +738,16 @@ int main(int argc, char *argv[]) {
 #endif
 #endif
 
 
   // Run frozen application
   // Run frozen application
-  PyImport_FrozenModules = blobinfo.pointers[0];
   retval = Py_FrozenMain(argc, argv);
   retval = Py_FrozenMain(argc, argv);
 
 
   fflush(stdout);
   fflush(stdout);
   fflush(stderr);
   fflush(stderr);
 
 
+#if PY_VERSION_HEX >= 0x030b0000
+  free((void *)PyImport_FrozenModules);
+  PyImport_FrozenModules = NULL;
+#endif
+
   unmap_blob(blob);
   unmap_blob(blob);
   return retval;
   return retval;
 }
 }