commit
1a92f12dfd
3
.idea/EG.iml
generated
3
.idea/EG.iml
generated
@ -2,9 +2,10 @@
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.10 virtualenv at ~/EG/venv (2)" jdkType="Python SDK" />
|
||||
<orderEntry type="jdk" jdkName="Python 3.10 (eg)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="PyDocumentationSettings">
|
||||
|
||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@ -3,5 +3,5 @@
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.12 (PythonProject)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 virtualenv at ~/EG/venv (2)" project-jdk-type="Python SDK" />
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (EG)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
@ -1,279 +1,271 @@
|
||||
# -*- coding: utf-8-*-
|
||||
"""
|
||||
Module : Env_Grid_Maker
|
||||
Author : Saifeddine ALOUI + code from Forklift 's code snippet could be found on panda3D's website
|
||||
Description :
|
||||
Creates a 3D implementation of grid that shows axes in 3 possible planes
|
||||
|
||||
"""
|
||||
from panda3d.core import *
|
||||
from direct.interval.IntervalGlobal import *
|
||||
|
||||
class Env_Grid_Maker:
|
||||
def __init__(self, XYPlaneShow = True, XZPlaneShow = False, YZPlaneShow = False, endCapLinesShow = True, XSize = 50, YSize = 50, ZSize = 50, gridStep = 10, subdiv = 10):
|
||||
#Create line objects
|
||||
self.axisLines = LineSegs()
|
||||
self.gridLines = LineSegs()
|
||||
self.subdivLines = LineSegs()
|
||||
|
||||
#Init passed variables
|
||||
self.XSize = XSize
|
||||
self.YSize = YSize
|
||||
self.ZSize = ZSize
|
||||
self.gridStep = gridStep
|
||||
self.subdiv = subdiv
|
||||
|
||||
#Init default variables
|
||||
|
||||
#Plane and end cap line visibility (1 is show, 0 is hide)
|
||||
self.XYPlaneShow = XYPlaneShow
|
||||
self.XZPlaneShow = XZPlaneShow
|
||||
self.YZPlaneShow = YZPlaneShow
|
||||
self.endCapLinesShow = endCapLinesShow
|
||||
|
||||
#Alpha variables for each plane
|
||||
#self.XYPlaneAlpha = 1
|
||||
#self.XZPlaneAlpha = 1
|
||||
#self.YZPlaneAlpha = 1
|
||||
|
||||
#Colors (RGBA passed as a VBase4 object)
|
||||
self.XAxisColor = VBase4(1, 0, 0, 1)
|
||||
self.YAxisColor = VBase4(0, 1, 0, 1)
|
||||
self.ZAxisColor = VBase4(0, 0, 1, 1)
|
||||
self.gridColor = VBase4(1, 1, 1, 1)
|
||||
self.subdivColor = VBase4(.35, .35, .35, 1)
|
||||
|
||||
#Line thicknesses (in pixels)
|
||||
self.axisThickness = 3
|
||||
self.gridThickness = 1
|
||||
self.subdivThickness = 1
|
||||
|
||||
|
||||
def create(self):
|
||||
#Set line thicknesses
|
||||
self.axisLines.setThickness(self.axisThickness)
|
||||
self.gridLines.setThickness(self.gridThickness)
|
||||
self.subdivLines.setThickness(self.subdivThickness)
|
||||
|
||||
if(self.XSize != 0):
|
||||
#Draw X axis line
|
||||
self.axisLines.setColor(self.XAxisColor)
|
||||
self.axisLines.moveTo(-(self.XSize), 0, 0)
|
||||
self.axisLines.drawTo(self.XSize, 0, 0)
|
||||
|
||||
if(self.YSize != 0):
|
||||
#Draw Y axis line
|
||||
self.axisLines.setColor(self.YAxisColor)
|
||||
self.axisLines.moveTo(0, -(self.YSize), 0)
|
||||
self.axisLines.drawTo(0, self.YSize, 0)
|
||||
|
||||
if(self.ZSize != 0):
|
||||
#Draw Z axis line
|
||||
self.axisLines.setColor(self.ZAxisColor)
|
||||
self.axisLines.moveTo(0, 0, -(self.ZSize))
|
||||
self.axisLines.drawTo(0, 0, self.ZSize)
|
||||
|
||||
#Check to see if primary grid lines should be drawn at all
|
||||
if(self.gridStep != 0):
|
||||
|
||||
#Draw primary grid lines
|
||||
self.gridLines.setColor(self.gridColor)
|
||||
|
||||
#Draw primary grid lines metering x axis if any x-length
|
||||
if(self.XSize != 0):
|
||||
if((self.YSize != 0) and (self.XYPlaneShow)):
|
||||
#Draw y lines across x axis starting from center moving out
|
||||
#XY Plane
|
||||
for x in self.myfrange(0, self.XSize, self.gridStep):
|
||||
self.gridLines.moveTo(x, -(self.YSize), 0)
|
||||
self.gridLines.drawTo(x, self.YSize, 0)
|
||||
self.gridLines.moveTo(-x, -(self.YSize), 0)
|
||||
self.gridLines.drawTo(-x, self.YSize, 0)
|
||||
|
||||
if(self.endCapLinesShow):
|
||||
#Draw endcap lines
|
||||
self.gridLines.moveTo(self.XSize, -(self.YSize), 0)
|
||||
self.gridLines.drawTo(self.XSize, self.YSize, 0)
|
||||
self.gridLines.moveTo(-(self.XSize), -(self.YSize), 0)
|
||||
self.gridLines.drawTo(-(self.XSize), self.YSize, 0)
|
||||
|
||||
if((self.ZSize != 0) and (self.XZPlaneShow)):
|
||||
#Draw z lines across x axis starting from center moving out
|
||||
#XZ Plane
|
||||
for x in self.myfrange(0, self.XSize, self.gridStep):
|
||||
self.gridLines.moveTo(x, 0, -(self.ZSize))
|
||||
self.gridLines.drawTo(x, 0, self.ZSize)
|
||||
self.gridLines.moveTo(-x, 0, -(self.ZSize))
|
||||
self.gridLines.drawTo(-x, 0, self.ZSize)
|
||||
|
||||
if(self.endCapLinesShow):
|
||||
#Draw endcap lines
|
||||
self.gridLines.moveTo(self.XSize, 0, -(self.ZSize))
|
||||
self.gridLines.drawTo(self.XSize, 0, self.ZSize)
|
||||
self.gridLines.moveTo(-(self.XSize), 0, -(self.ZSize))
|
||||
self.gridLines.drawTo(-(self.XSize), 0, self.ZSize)
|
||||
|
||||
#Draw primary grid lines metering y axis if any y-length
|
||||
if(self.YSize != 0):
|
||||
|
||||
if((self.YSize != 0) and (self.XYPlaneShow)):
|
||||
#Draw x lines across y axis
|
||||
#XY Plane
|
||||
for y in self.myfrange(0, self.YSize, self.gridStep):
|
||||
self.gridLines.moveTo(-(self.XSize), y, 0)
|
||||
self.gridLines.drawTo(self.XSize, y, 0)
|
||||
self.gridLines.moveTo(-(self.XSize), -y, 0)
|
||||
self.gridLines.drawTo(self.XSize, -y, 0)
|
||||
|
||||
if(self.endCapLinesShow):
|
||||
#Draw endcap lines
|
||||
self.gridLines.moveTo(-(self.XSize), self.YSize, 0)
|
||||
self.gridLines.drawTo(self.XSize, self.YSize, 0)
|
||||
self.gridLines.moveTo(-(self.XSize), -(self.YSize), 0)
|
||||
self.gridLines.drawTo(self.XSize, -(self.YSize), 0)
|
||||
|
||||
if((self.ZSize != 0) and (self.YZPlaneShow)):
|
||||
#Draw z lines across y axis
|
||||
#YZ Plane
|
||||
for y in self.myfrange(0, self.YSize, self.gridStep):
|
||||
self.gridLines.moveTo(0, y, -(self.ZSize))
|
||||
self.gridLines.drawTo(0, y, self.ZSize)
|
||||
self.gridLines.moveTo(0, -y, -(self.ZSize))
|
||||
self.gridLines.drawTo(0, -y, self.ZSize)
|
||||
|
||||
if(self.endCapLinesShow):
|
||||
#Draw endcap lines
|
||||
self.gridLines.moveTo(0, self.YSize, -(self.ZSize))
|
||||
self.gridLines.drawTo(0, self.YSize, self.ZSize)
|
||||
self.gridLines.moveTo(0, -(self.YSize), -(self.ZSize))
|
||||
self.gridLines.drawTo(0, -(self.YSize), self.ZSize)
|
||||
|
||||
#Draw primary grid lines metering z axis if any z-length
|
||||
if(self.ZSize != 0):
|
||||
if((self.XSize != 0) and (self.XZPlaneShow)):
|
||||
#Draw x lines across z axis
|
||||
#XZ Plane
|
||||
for z in self.myfrange(0, self.ZSize, self.gridStep):
|
||||
self.gridLines.moveTo(-(self.XSize), 0, z)
|
||||
self.gridLines.drawTo(self.XSize, 0, z)
|
||||
self.gridLines.moveTo(-(self.XSize), 0, -z)
|
||||
self.gridLines.drawTo(self.XSize, 0, -z)
|
||||
|
||||
if(self.endCapLinesShow):
|
||||
#Draw endcap lines
|
||||
self.gridLines.moveTo(-(self.XSize), 0, self.ZSize)
|
||||
self.gridLines.drawTo(self.XSize, 0, self.ZSize)
|
||||
self.gridLines.moveTo(-(self.XSize), 0, -(self.ZSize))
|
||||
self.gridLines.drawTo(self.XSize, 0, -(self.ZSize))
|
||||
|
||||
if((self.YSize != 0) and (self.YZPlaneShow)):
|
||||
#Draw y lines across z axis
|
||||
#YZ Plane
|
||||
for z in self.myfrange(0, self.ZSize, self.gridStep):
|
||||
self.gridLines.moveTo(0, -(self.YSize), z)
|
||||
self.gridLines.drawTo(0, self.YSize, z)
|
||||
self.gridLines.moveTo(0, -(self.YSize), -z)
|
||||
self.gridLines.drawTo(0, self.YSize, -z)
|
||||
|
||||
if(self.endCapLinesShow):
|
||||
#Draw endcap lines
|
||||
self.gridLines.moveTo(0, -(self.YSize), self.ZSize)
|
||||
self.gridLines.drawTo(0, self.YSize, self.ZSize)
|
||||
self.gridLines.moveTo(0, -(self.YSize), -(self.ZSize))
|
||||
self.gridLines.drawTo(0, self.YSize, -(self.ZSize))
|
||||
|
||||
#Check to see if secondary grid lines should be drawn
|
||||
if(self.subdiv != 0):
|
||||
|
||||
#Draw secondary grid lines
|
||||
self.subdivLines.setColor(self.subdivColor)
|
||||
|
||||
if(self.XSize != 0):
|
||||
adjustedstep = self.gridStep / self.subdiv
|
||||
if((self.YSize != 0) and (self.XYPlaneShow)):
|
||||
#Draw y lines across x axis starting from center moving out
|
||||
#XY
|
||||
for x in self.myfrange(0, self.XSize, adjustedstep):
|
||||
self.subdivLines.moveTo(x, -(self.YSize), 0)
|
||||
self.subdivLines.drawTo(x, self.YSize, 0)
|
||||
self.subdivLines.moveTo(-x, -(self.YSize), 0)
|
||||
self.subdivLines.drawTo(-x, self.YSize, 0)
|
||||
|
||||
if((self.ZSize != 0) and (self.XZPlaneShow)):
|
||||
#Draw z lines across x axis starting from center moving out
|
||||
#XZ
|
||||
for x in self.myfrange(0, self.XSize, adjustedstep):
|
||||
self.subdivLines.moveTo(x, 0, -(self.ZSize))
|
||||
self.subdivLines.drawTo(x, 0, self.ZSize)
|
||||
self.subdivLines.moveTo(-x, 0, -(self.ZSize))
|
||||
self.subdivLines.drawTo(-x, 0, self.ZSize)
|
||||
|
||||
if(self.YSize != 0):
|
||||
if((self.YSize != 0) and (self.XYPlaneShow)):
|
||||
#Draw x lines across y axis
|
||||
#XY
|
||||
for y in self.myfrange(0, self.YSize, adjustedstep):
|
||||
self.subdivLines.moveTo(-(self.XSize), y, 0)
|
||||
self.subdivLines.drawTo(self.XSize, y, 0)
|
||||
self.subdivLines.moveTo(-(self.XSize), -y, 0)
|
||||
self.subdivLines.drawTo(self.XSize, -y, 0)
|
||||
if((self.ZSize != 0) and (self.YZPlaneShow)):
|
||||
#Draw z lines across y axis
|
||||
#YZ
|
||||
for y in self.myfrange(0, self.YSize, adjustedstep):
|
||||
self.subdivLines.moveTo(0, y, -(self.ZSize))
|
||||
self.subdivLines.drawTo(0, y, self.ZSize)
|
||||
self.subdivLines.moveTo(0, -y, -(self.ZSize))
|
||||
self.subdivLines.drawTo(0, -y, self.ZSize)
|
||||
|
||||
if(self.ZSize != 0):
|
||||
|
||||
if((self.XSize != 0) and (self.XZPlaneShow)):
|
||||
#Draw x lines across z axis
|
||||
#XZ
|
||||
for z in self.myfrange(0, self.ZSize, adjustedstep):
|
||||
self.subdivLines.moveTo(-(self.XSize), 0, z)
|
||||
self.subdivLines.drawTo(self.XSize, 0, z)
|
||||
self.subdivLines.moveTo(-(self.XSize), 0, -z)
|
||||
self.subdivLines.drawTo(self.XSize, 0, -z)
|
||||
|
||||
if((self.YSize != 0) and (self.YZPlaneShow)):
|
||||
#Draw y lines across z axis
|
||||
#YZ
|
||||
for z in self.myfrange(0, self.ZSize, adjustedstep):
|
||||
self.subdivLines.moveTo(0, -(self.YSize), z)
|
||||
self.subdivLines.drawTo(0, self.YSize, z)
|
||||
self.subdivLines.moveTo(0, -(self.YSize), -z)
|
||||
self.subdivLines.drawTo(0, self.YSize, -z)
|
||||
|
||||
#Create ThreeAxisGrid nodes and nodepaths
|
||||
#Create parent node and path
|
||||
self.parentNode = PandaNode('threeaxisgrid-parentnode')
|
||||
self.parentNodePath = NodePath(self.parentNode)
|
||||
|
||||
#Create axis lines node and path, then reparent
|
||||
self.axisLinesNode = self.axisLines.create()
|
||||
self.axisLinesNodePath = NodePath(self.axisLinesNode)
|
||||
self.axisLinesNodePath.reparentTo(self.parentNodePath)
|
||||
|
||||
#Create grid lines node and path, then reparent
|
||||
self.gridLinesNode = self.gridLines.create()
|
||||
self.gridLinesNodePath = NodePath(self.gridLinesNode)
|
||||
self.gridLinesNodePath.reparentTo(self.parentNodePath)
|
||||
|
||||
#Create subdivision lines node and path then reparent
|
||||
self.subdivLinesNode = self.subdivLines.create()
|
||||
self.subdivLinesNodePath = NodePath(self.subdivLinesNode)
|
||||
self.subdivLinesNodePath.reparentTo(self.parentNodePath)
|
||||
|
||||
return self.parentNodePath
|
||||
def myfrange(self, start, stop=None, step=None):
|
||||
if stop is None:
|
||||
stop = float(start)
|
||||
start = 0.0
|
||||
if step is None:
|
||||
step = 1.0
|
||||
cur = float(start)
|
||||
while cur < stop:
|
||||
yield cur
|
||||
from panda3d.core import *
|
||||
from direct.interval.IntervalGlobal import *
|
||||
|
||||
class Env_Grid_Maker:
|
||||
def __init__(self, XYPlaneShow = True, XZPlaneShow = False, YZPlaneShow = False, endCapLinesShow = True, XSize = 50, YSize = 50, ZSize = 50, gridStep = 10, subdiv = 10):
|
||||
#Create line objects
|
||||
self.axisLines = LineSegs()
|
||||
self.gridLines = LineSegs()
|
||||
self.subdivLines = LineSegs()
|
||||
|
||||
#Init passed variables
|
||||
self.XSize = XSize
|
||||
self.YSize = YSize
|
||||
self.ZSize = ZSize
|
||||
self.gridStep = gridStep
|
||||
self.subdiv = subdiv
|
||||
|
||||
#Init default variables
|
||||
|
||||
#Plane and end cap line visibility (1 is show, 0 is hide)
|
||||
self.XYPlaneShow = XYPlaneShow
|
||||
self.XZPlaneShow = XZPlaneShow
|
||||
self.YZPlaneShow = YZPlaneShow
|
||||
self.endCapLinesShow = endCapLinesShow
|
||||
|
||||
#Alpha variables for each plane
|
||||
#self.XYPlaneAlpha = 1
|
||||
#self.XZPlaneAlpha = 1
|
||||
#self.YZPlaneAlpha = 1
|
||||
|
||||
#Colors (RGBA passed as a VBase4 object)
|
||||
self.XAxisColor = VBase4(1, 0, 0, 1)
|
||||
self.YAxisColor = VBase4(0, 1, 0, 1)
|
||||
self.ZAxisColor = VBase4(0, 0, 1, 1)
|
||||
self.gridColor = VBase4(1, 1, 1, 1)
|
||||
self.subdivColor = VBase4(.35, .35, .35, 1)
|
||||
|
||||
#Line thicknesses (in pixels)
|
||||
self.axisThickness = 3
|
||||
self.gridThickness = 1
|
||||
self.subdivThickness = 1
|
||||
|
||||
|
||||
def create(self):
|
||||
#Set line thicknesses
|
||||
self.axisLines.setThickness(self.axisThickness)
|
||||
self.gridLines.setThickness(self.gridThickness)
|
||||
self.subdivLines.setThickness(self.subdivThickness)
|
||||
|
||||
if(self.XSize != 0):
|
||||
#Draw X axis line
|
||||
self.axisLines.setColor(self.XAxisColor)
|
||||
self.axisLines.moveTo(-(self.XSize), 0, 0)
|
||||
self.axisLines.drawTo(self.XSize, 0, 0)
|
||||
|
||||
if(self.YSize != 0):
|
||||
#Draw Y axis line
|
||||
self.axisLines.setColor(self.YAxisColor)
|
||||
self.axisLines.moveTo(0, -(self.YSize), 0)
|
||||
self.axisLines.drawTo(0, self.YSize, 0)
|
||||
|
||||
if(self.ZSize != 0):
|
||||
#Draw Z axis line
|
||||
self.axisLines.setColor(self.ZAxisColor)
|
||||
self.axisLines.moveTo(0, 0, -(self.ZSize))
|
||||
self.axisLines.drawTo(0, 0, self.ZSize)
|
||||
|
||||
#Check to see if primary grid lines should be drawn at all
|
||||
if(self.gridStep != 0):
|
||||
|
||||
#Draw primary grid lines
|
||||
self.gridLines.setColor(self.gridColor)
|
||||
|
||||
#Draw primary grid lines metering x axis if any x-length
|
||||
if(self.XSize != 0):
|
||||
if((self.YSize != 0) and (self.XYPlaneShow)):
|
||||
#Draw y lines across x axis starting from center moving out
|
||||
#XY Plane
|
||||
for x in self.myfrange(0, self.XSize, self.gridStep):
|
||||
self.gridLines.moveTo(x, -(self.YSize), 0)
|
||||
self.gridLines.drawTo(x, self.YSize, 0)
|
||||
self.gridLines.moveTo(-x, -(self.YSize), 0)
|
||||
self.gridLines.drawTo(-x, self.YSize, 0)
|
||||
|
||||
if(self.endCapLinesShow):
|
||||
#Draw endcap lines
|
||||
self.gridLines.moveTo(self.XSize, -(self.YSize), 0)
|
||||
self.gridLines.drawTo(self.XSize, self.YSize, 0)
|
||||
self.gridLines.moveTo(-(self.XSize), -(self.YSize), 0)
|
||||
self.gridLines.drawTo(-(self.XSize), self.YSize, 0)
|
||||
|
||||
if((self.ZSize != 0) and (self.XZPlaneShow)):
|
||||
#Draw z lines across x axis starting from center moving out
|
||||
#XZ Plane
|
||||
for x in self.myfrange(0, self.XSize, self.gridStep):
|
||||
self.gridLines.moveTo(x, 0, -(self.ZSize))
|
||||
self.gridLines.drawTo(x, 0, self.ZSize)
|
||||
self.gridLines.moveTo(-x, 0, -(self.ZSize))
|
||||
self.gridLines.drawTo(-x, 0, self.ZSize)
|
||||
|
||||
if(self.endCapLinesShow):
|
||||
#Draw endcap lines
|
||||
self.gridLines.moveTo(self.XSize, 0, -(self.ZSize))
|
||||
self.gridLines.drawTo(self.XSize, 0, self.ZSize)
|
||||
self.gridLines.moveTo(-(self.XSize), 0, -(self.ZSize))
|
||||
self.gridLines.drawTo(-(self.XSize), 0, self.ZSize)
|
||||
|
||||
#Draw primary grid lines metering y axis if any y-length
|
||||
if(self.YSize != 0):
|
||||
|
||||
if((self.YSize != 0) and (self.XYPlaneShow)):
|
||||
#Draw x lines across y axis
|
||||
#XY Plane
|
||||
for y in self.myfrange(0, self.YSize, self.gridStep):
|
||||
self.gridLines.moveTo(-(self.XSize), y, 0)
|
||||
self.gridLines.drawTo(self.XSize, y, 0)
|
||||
self.gridLines.moveTo(-(self.XSize), -y, 0)
|
||||
self.gridLines.drawTo(self.XSize, -y, 0)
|
||||
|
||||
if(self.endCapLinesShow):
|
||||
#Draw endcap lines
|
||||
self.gridLines.moveTo(-(self.XSize), self.YSize, 0)
|
||||
self.gridLines.drawTo(self.XSize, self.YSize, 0)
|
||||
self.gridLines.moveTo(-(self.XSize), -(self.YSize), 0)
|
||||
self.gridLines.drawTo(self.XSize, -(self.YSize), 0)
|
||||
|
||||
if((self.ZSize != 0) and (self.YZPlaneShow)):
|
||||
#Draw z lines across y axis
|
||||
#YZ Plane
|
||||
for y in self.myfrange(0, self.YSize, self.gridStep):
|
||||
self.gridLines.moveTo(0, y, -(self.ZSize))
|
||||
self.gridLines.drawTo(0, y, self.ZSize)
|
||||
self.gridLines.moveTo(0, -y, -(self.ZSize))
|
||||
self.gridLines.drawTo(0, -y, self.ZSize)
|
||||
|
||||
if(self.endCapLinesShow):
|
||||
#Draw endcap lines
|
||||
self.gridLines.moveTo(0, self.YSize, -(self.ZSize))
|
||||
self.gridLines.drawTo(0, self.YSize, self.ZSize)
|
||||
self.gridLines.moveTo(0, -(self.YSize), -(self.ZSize))
|
||||
self.gridLines.drawTo(0, -(self.YSize), self.ZSize)
|
||||
|
||||
#Draw primary grid lines metering z axis if any z-length
|
||||
if(self.ZSize != 0):
|
||||
if((self.XSize != 0) and (self.XZPlaneShow)):
|
||||
#Draw x lines across z axis
|
||||
#XZ Plane
|
||||
for z in self.myfrange(0, self.ZSize, self.gridStep):
|
||||
self.gridLines.moveTo(-(self.XSize), 0, z)
|
||||
self.gridLines.drawTo(self.XSize, 0, z)
|
||||
self.gridLines.moveTo(-(self.XSize), 0, -z)
|
||||
self.gridLines.drawTo(self.XSize, 0, -z)
|
||||
|
||||
if(self.endCapLinesShow):
|
||||
#Draw endcap lines
|
||||
self.gridLines.moveTo(-(self.XSize), 0, self.ZSize)
|
||||
self.gridLines.drawTo(self.XSize, 0, self.ZSize)
|
||||
self.gridLines.moveTo(-(self.XSize), 0, -(self.ZSize))
|
||||
self.gridLines.drawTo(self.XSize, 0, -(self.ZSize))
|
||||
|
||||
if((self.YSize != 0) and (self.YZPlaneShow)):
|
||||
#Draw y lines across z axis
|
||||
#YZ Plane
|
||||
for z in self.myfrange(0, self.ZSize, self.gridStep):
|
||||
self.gridLines.moveTo(0, -(self.YSize), z)
|
||||
self.gridLines.drawTo(0, self.YSize, z)
|
||||
self.gridLines.moveTo(0, -(self.YSize), -z)
|
||||
self.gridLines.drawTo(0, self.YSize, -z)
|
||||
|
||||
if(self.endCapLinesShow):
|
||||
#Draw endcap lines
|
||||
self.gridLines.moveTo(0, -(self.YSize), self.ZSize)
|
||||
self.gridLines.drawTo(0, self.YSize, self.ZSize)
|
||||
self.gridLines.moveTo(0, -(self.YSize), -(self.ZSize))
|
||||
self.gridLines.drawTo(0, self.YSize, -(self.ZSize))
|
||||
|
||||
#Check to see if secondary grid lines should be drawn
|
||||
if(self.subdiv != 0):
|
||||
|
||||
#Draw secondary grid lines
|
||||
self.subdivLines.setColor(self.subdivColor)
|
||||
|
||||
if(self.XSize != 0):
|
||||
adjustedstep = self.gridStep / self.subdiv
|
||||
if((self.YSize != 0) and (self.XYPlaneShow)):
|
||||
#Draw y lines across x axis starting from center moving out
|
||||
#XY
|
||||
for x in self.myfrange(0, self.XSize, adjustedstep):
|
||||
self.subdivLines.moveTo(x, -(self.YSize), 0)
|
||||
self.subdivLines.drawTo(x, self.YSize, 0)
|
||||
self.subdivLines.moveTo(-x, -(self.YSize), 0)
|
||||
self.subdivLines.drawTo(-x, self.YSize, 0)
|
||||
|
||||
if((self.ZSize != 0) and (self.XZPlaneShow)):
|
||||
#Draw z lines across x axis starting from center moving out
|
||||
#XZ
|
||||
for x in self.myfrange(0, self.XSize, adjustedstep):
|
||||
self.subdivLines.moveTo(x, 0, -(self.ZSize))
|
||||
self.subdivLines.drawTo(x, 0, self.ZSize)
|
||||
self.subdivLines.moveTo(-x, 0, -(self.ZSize))
|
||||
self.subdivLines.drawTo(-x, 0, self.ZSize)
|
||||
|
||||
if(self.YSize != 0):
|
||||
if((self.YSize != 0) and (self.XYPlaneShow)):
|
||||
#Draw x lines across y axis
|
||||
#XY
|
||||
for y in self.myfrange(0, self.YSize, adjustedstep):
|
||||
self.subdivLines.moveTo(-(self.XSize), y, 0)
|
||||
self.subdivLines.drawTo(self.XSize, y, 0)
|
||||
self.subdivLines.moveTo(-(self.XSize), -y, 0)
|
||||
self.subdivLines.drawTo(self.XSize, -y, 0)
|
||||
if((self.ZSize != 0) and (self.YZPlaneShow)):
|
||||
#Draw z lines across y axis
|
||||
#YZ
|
||||
for y in self.myfrange(0, self.YSize, adjustedstep):
|
||||
self.subdivLines.moveTo(0, y, -(self.ZSize))
|
||||
self.subdivLines.drawTo(0, y, self.ZSize)
|
||||
self.subdivLines.moveTo(0, -y, -(self.ZSize))
|
||||
self.subdivLines.drawTo(0, -y, self.ZSize)
|
||||
|
||||
if(self.ZSize != 0):
|
||||
|
||||
if((self.XSize != 0) and (self.XZPlaneShow)):
|
||||
#Draw x lines across z axis
|
||||
#XZ
|
||||
for z in self.myfrange(0, self.ZSize, adjustedstep):
|
||||
self.subdivLines.moveTo(-(self.XSize), 0, z)
|
||||
self.subdivLines.drawTo(self.XSize, 0, z)
|
||||
self.subdivLines.moveTo(-(self.XSize), 0, -z)
|
||||
self.subdivLines.drawTo(self.XSize, 0, -z)
|
||||
|
||||
if((self.YSize != 0) and (self.YZPlaneShow)):
|
||||
#Draw y lines across z axis
|
||||
#YZ
|
||||
for z in self.myfrange(0, self.ZSize, adjustedstep):
|
||||
self.subdivLines.moveTo(0, -(self.YSize), z)
|
||||
self.subdivLines.drawTo(0, self.YSize, z)
|
||||
self.subdivLines.moveTo(0, -(self.YSize), -z)
|
||||
self.subdivLines.drawTo(0, self.YSize, -z)
|
||||
|
||||
#Create ThreeAxisGrid nodes and nodepaths
|
||||
#Create parent node and path
|
||||
self.parentNode = PandaNode('threeaxisgrid-parentnode')
|
||||
self.parentNodePath = NodePath(self.parentNode)
|
||||
|
||||
#Create axis lines node and path, then reparent
|
||||
self.axisLinesNode = self.axisLines.create()
|
||||
self.axisLinesNodePath = NodePath(self.axisLinesNode)
|
||||
self.axisLinesNodePath.reparentTo(self.parentNodePath)
|
||||
|
||||
#Create grid lines node and path, then reparent
|
||||
self.gridLinesNode = self.gridLines.create()
|
||||
self.gridLinesNodePath = NodePath(self.gridLinesNode)
|
||||
self.gridLinesNodePath.reparentTo(self.parentNodePath)
|
||||
|
||||
#Create subdivision lines node and path then reparent
|
||||
self.subdivLinesNode = self.subdivLines.create()
|
||||
self.subdivLinesNodePath = NodePath(self.subdivLinesNode)
|
||||
self.subdivLinesNodePath.reparentTo(self.parentNodePath)
|
||||
|
||||
return self.parentNodePath
|
||||
def myfrange(self, start, stop=None, step=None):
|
||||
if stop is None:
|
||||
stop = float(start)
|
||||
start = 0.0
|
||||
if step is None:
|
||||
step = 1.0
|
||||
cur = float(start)
|
||||
while cur < stop:
|
||||
yield cur
|
||||
cur += step
|
||||
@ -1,2 +1,2 @@
|
||||
name="QPanda3D"
|
||||
name="QMeta3D"
|
||||
__all__ = ["Env_Grid_Maker"]
|
||||
@ -1,214 +1,192 @@
|
||||
# -*- coding: utf-8-*-
|
||||
"""
|
||||
Module : Panda3DWorld
|
||||
Author : Saifeddine ALOUI
|
||||
Description :
|
||||
Inherit this object to create your custom world
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
|
||||
from core.CustomMouseController import CustomMouseController
|
||||
|
||||
# 获取 RenderPipelineFile 的路径
|
||||
render_pipeline_path = './RenderPipelineFile'
|
||||
# 将该路径添加到 sys.path 中,确保 Python 能够找到它
|
||||
project_root = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, project_root)
|
||||
sys.path.insert(0, render_pipeline_path)
|
||||
|
||||
# 现在你可以导入 RenderPipelineFile 中的模块了
|
||||
# 例如,如果你想导入 RenderPipelineFile 中的 RenderPipeline 模块
|
||||
from RenderPipelineFile.rpcore import RenderPipeline
|
||||
_global_render_pipeline = None
|
||||
|
||||
# PyQt imports
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
# Panda imports
|
||||
from panda3d.core import *
|
||||
# from panda3d.core import loadPrcFileData
|
||||
# loadPrcFileData("", "window-type none") # Set Panda to draw its main window in an offscreen buffer
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from panda3d.core import GraphicsOutput, Texture, ConfigVariableManager, WindowProperties
|
||||
|
||||
# Set up Panda environment
|
||||
from direct.showbase.ShowBase import ShowBase
|
||||
import platform
|
||||
|
||||
# Local imports
|
||||
from QPanda3D.QMouseWatcherNode import QMouseWatcherNode
|
||||
|
||||
from RenderPipelineFile.rpcore.render_target import RenderTarget
|
||||
__all__ = ["Panda3DWorld"]
|
||||
|
||||
_global_world_instance=None
|
||||
import builtins
|
||||
|
||||
|
||||
class Panda3DWorld(ShowBase):
|
||||
"""
|
||||
Panda3DWorld : A class to handle all panda3D world manipulation
|
||||
"""
|
||||
|
||||
def __init__(self, width=1380, height=750, is_fullscreen=False, size=1.0, clear_color=LVecBase4f(0, 0.5, 0, 1),
|
||||
name="qpanda3D"):
|
||||
|
||||
global _global_world_instance
|
||||
global _global_render_pipeline
|
||||
|
||||
_global_world_instance = self
|
||||
|
||||
sort = -100
|
||||
self.parent = None
|
||||
|
||||
# 设置基本配置
|
||||
loadPrcFileData("", "show-frame-rate-meter 0")
|
||||
loadPrcFileData("", "window-type offscreen") # 设置为离屏渲染
|
||||
loadPrcFileData("", f"win-size {width} {height}")
|
||||
loadPrcFileData("", "win-fixed-size #f") # 允许窗口调整大小
|
||||
|
||||
# 🚀 VR性能优化配置
|
||||
loadPrcFileData("", "prefer-single-buffer true") # 减少缓冲区交换开销
|
||||
loadPrcFileData("", "gl-force-flush false") # 避免强制glFlush导致的性能损失
|
||||
loadPrcFileData("", "sync-video false") # 禁用默认VSync,让OpenVR控制
|
||||
loadPrcFileData("", "support-stencil false") # 禁用不必要的模板缓冲区
|
||||
loadPrcFileData("", "clock-mode non-real-time") # 禁用Panda3D帧率控制,让OpenVR控制
|
||||
# loadPrcFileData("", "gl-debug true") # 调试时可启用OpenGL调试
|
||||
|
||||
if (is_fullscreen):
|
||||
loadPrcFileData("", "fullscreen #t")
|
||||
|
||||
self.render_pipeline = RenderPipeline()
|
||||
self.render_pipeline.pre_showbase_init()
|
||||
|
||||
ShowBase.__init__(self)
|
||||
|
||||
# 初始化渲染管线并设置可调整大小的标志
|
||||
self.render_pipeline.create(self)
|
||||
_global_render_pipeline = self.render_pipeline
|
||||
|
||||
# 创建 Qt 能读的 RGBA8 贴图
|
||||
self.qt_output_tex = Texture("qt_output_tex")
|
||||
self.qt_output_tex.set_format(Texture.F_rgba8)
|
||||
self.qt_output_tex.set_component_type(Texture.T_unsigned_byte)
|
||||
|
||||
# # 获取图形管线对象
|
||||
# gsg = self.win.getGsg()
|
||||
# host = gsg.getEngine().getHost()
|
||||
|
||||
self.win.add_render_texture(self.qt_output_tex, GraphicsOutput.RTM_copy_ram)
|
||||
|
||||
#self.screenTexture = Texture()
|
||||
#self.screenTexture.setMinfilter(Texture.FTLinear)
|
||||
#self.screenTexture.setFormat(Texture.FRgba32)
|
||||
#self.screenTexture.set_wrap_u(Texture.WM_clamp)
|
||||
#self.screenTexture.set_wrap_v(Texture.WM_clamp)
|
||||
|
||||
# buff_size_x = int(self.win.get_x_size() * size)
|
||||
# buff_size_y = int(self.win.get_y_size() * size)
|
||||
# winprops = WindowProperties()
|
||||
# winprops.set_size(buff_size_x, buff_size_y)
|
||||
#
|
||||
#
|
||||
# props = FrameBufferProperties()
|
||||
# props.set_rgb_color(True)
|
||||
# props.set_rgba_bits(8, 8, 8, 8)
|
||||
# props.set_depth_bits(8)
|
||||
|
||||
# self.buff = self.graphicsEngine.make_output(
|
||||
# self.pipe, name, sort,
|
||||
# props, winprops,
|
||||
# GraphicsPipe.BF_resizeable,
|
||||
# self.win.get_gsg(), self.win)
|
||||
|
||||
#self.screenTexture = render_pipeline._final_stage.target.color_tex
|
||||
|
||||
#self.buff.addRenderTexture(self.screenTexture, GraphicsOutput.RTMCopyRam)
|
||||
# self.buff.set_sort(sort)
|
||||
|
||||
|
||||
|
||||
#self.cam = self.makeCamera(self.buff)
|
||||
#self.render_pipeline._showbase.cam=self.makeCamera(self.buff)
|
||||
|
||||
#self.render_pipeline._showbase.cam=self.makeCamera(self.buff)
|
||||
|
||||
#self.render_pipeline._showbase.camera.reparentTo(self.render)
|
||||
#base.camera.reparentTo(self.render)
|
||||
#self.cam.reparentTo(self.render) # 可选同步
|
||||
|
||||
#render_pipeline.set_camera(self.cam)
|
||||
|
||||
#添加渲染效果
|
||||
#self.cam = self.render_pipeline._showbase.cam
|
||||
#self.camNode = self.cam.node()
|
||||
#self.camLens = self.camNode.get_lens()
|
||||
self.render_pipeline._showbase.camera = self.render_pipeline._showbase.cam
|
||||
#self.render_pipeline.daytime_mgr.update()
|
||||
|
||||
|
||||
# if clear_color is None:
|
||||
# self.buff.set_clear_active(GraphicsOutput.RTPColor, False)
|
||||
# else:
|
||||
# self.buff.set_clear_color(clear_color)
|
||||
# self.buff.set_clear_active(GraphicsOutput.RTPColor, True)
|
||||
|
||||
# self.disableMouse()
|
||||
self.mouse_controller = CustomMouseController(self)
|
||||
self.mouse_controller.setUp()
|
||||
|
||||
# 添加错误处理钩子
|
||||
self.accept("transform_state_error", self._handle_transform_error)
|
||||
|
||||
def _handle_transform_error(self):
|
||||
"""处理TransformState相关的错误"""
|
||||
try:
|
||||
from panda3d.core import TransformState, RenderState
|
||||
TransformState.clear_cache()
|
||||
RenderState.clear_cache()
|
||||
print("已清理TransformState和RenderState缓存")
|
||||
except Exception as e:
|
||||
print(f"清理缓存时出错: {e}")
|
||||
|
||||
def render_pipeline(self):
|
||||
"""获取 RenderPipeline 实例"""
|
||||
return self._render_pipeline
|
||||
|
||||
|
||||
def set_parent(self, parent: QWidget):
|
||||
self.parent = parent
|
||||
self.mouseWatcherNode = QMouseWatcherNode(parent)
|
||||
|
||||
def getAspectRatio(self, win = None):
|
||||
if win is None and self.parent is not None:
|
||||
return float(self.parent.width()) / float(self.parent.height())
|
||||
else:
|
||||
return super().getAspectRatio(win)
|
||||
|
||||
def get_render_pipeline():
|
||||
"""获取全局 RenderPipeline 单例"""
|
||||
if _global_render_pipeline is None:
|
||||
raise RuntimeError(
|
||||
"RenderPipeline has not been initialized yet. Please create a Panda3DWorld instance first.")
|
||||
return _global_render_pipeline
|
||||
|
||||
def resize_buffer(self, width: int, height: int):
|
||||
"""根据新窗口尺寸调整 Panda3D 渲染输出尺寸"""
|
||||
# 设置 Panda3D 的窗口尺寸(offscreen 模式下对应输出区域)
|
||||
props = WindowProperties()
|
||||
props.set_size(width, height)
|
||||
self.win.request_properties(props)
|
||||
|
||||
# 重新分配输出贴图的大小
|
||||
self.qt_output_tex.set_x_size(width)
|
||||
self.qt_output_tex.set_y_size(height)
|
||||
|
||||
# 更新 lens 的 aspect ratio
|
||||
if self.camLens:
|
||||
self.camLens.set_film_size(width, height) # 或 set_aspect_ratio(width / height)
|
||||
|
||||
# 强制更新窗口(有时在 Qt 内嵌时需要)
|
||||
import sys
|
||||
import os
|
||||
|
||||
from core.CustomMouseController import CustomMouseController
|
||||
|
||||
# 获取 RenderPipelineFile 的路径
|
||||
render_pipeline_path = './RenderPipelineFile'
|
||||
# 将该路径添加到 sys.path 中,确保 Python 能够找到它
|
||||
project_root = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, project_root)
|
||||
sys.path.insert(0, render_pipeline_path)
|
||||
|
||||
from RenderPipelineFile.rpcore import RenderPipeline
|
||||
_global_render_pipeline = None
|
||||
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
from panda3d.core import *
|
||||
from panda3d.core import GraphicsOutput, Texture, ConfigVariableManager, WindowProperties
|
||||
|
||||
from direct.showbase.ShowBase import ShowBase
|
||||
import platform
|
||||
|
||||
from QMeta3D.QMouseWatcherNode import QMouseWatcherNode
|
||||
|
||||
from RenderPipelineFile.rpcore.render_target import RenderTarget
|
||||
__all__ = ["Meta3DWorld"]
|
||||
|
||||
_global_world_instance=None
|
||||
import builtins
|
||||
|
||||
|
||||
class Meta3DWorld(ShowBase):
|
||||
def __init__(self, width=1380, height=750, is_fullscreen=False, size=1.0, clear_color=LVecBase4f(0, 0.5, 0, 1),
|
||||
name="qMeta3D"):
|
||||
|
||||
global _global_world_instance
|
||||
global _global_render_pipeline
|
||||
|
||||
_global_world_instance = self
|
||||
|
||||
sort = -100
|
||||
self.parent = None
|
||||
|
||||
# 设置基本配置
|
||||
loadPrcFileData("", "show-frame-rate-meter 0")
|
||||
loadPrcFileData("", "window-type offscreen") # 设置为离屏渲染
|
||||
loadPrcFileData("", f"win-size {width} {height}")
|
||||
loadPrcFileData("", "win-fixed-size #f") # 允许窗口调整大小
|
||||
|
||||
# 🚀 VR性能优化配置
|
||||
loadPrcFileData("", "prefer-single-buffer true") # 减少缓冲区交换开销
|
||||
loadPrcFileData("", "gl-force-flush false") # 避免强制glFlush导致的性能损失
|
||||
loadPrcFileData("", "sync-video false") # 禁用默认VSync,让OpenVR控制
|
||||
loadPrcFileData("", "support-stencil false") # 禁用不必要的模板缓冲区
|
||||
loadPrcFileData("", "clock-mode non-real-time")
|
||||
# loadPrcFileData("", "gl-debug true")
|
||||
|
||||
if (is_fullscreen):
|
||||
loadPrcFileData("", "fullscreen #t")
|
||||
|
||||
self.render_pipeline = RenderPipeline()
|
||||
self.render_pipeline.pre_showbase_init()
|
||||
|
||||
ShowBase.__init__(self)
|
||||
|
||||
# 初始化渲染管线并设置可调整大小的标志
|
||||
self.render_pipeline.create(self)
|
||||
_global_render_pipeline = self.render_pipeline
|
||||
|
||||
# 创建 Qt 能读的 RGBA8 贴图
|
||||
self.qt_output_tex = Texture("qt_output_tex")
|
||||
self.qt_output_tex.set_format(Texture.F_rgba8)
|
||||
self.qt_output_tex.set_component_type(Texture.T_unsigned_byte)
|
||||
|
||||
# # 获取图形管线对象
|
||||
# gsg = self.win.getGsg()
|
||||
# host = gsg.getEngine().getHost()
|
||||
|
||||
self.win.add_render_texture(self.qt_output_tex, GraphicsOutput.RTM_copy_ram)
|
||||
|
||||
#self.screenTexture = Texture()
|
||||
#self.screenTexture.setMinfilter(Texture.FTLinear)
|
||||
#self.screenTexture.setFormat(Texture.FRgba32)
|
||||
#self.screenTexture.set_wrap_u(Texture.WM_clamp)
|
||||
#self.screenTexture.set_wrap_v(Texture.WM_clamp)
|
||||
|
||||
# buff_size_x = int(self.win.get_x_size() * size)
|
||||
# buff_size_y = int(self.win.get_y_size() * size)
|
||||
# winprops = WindowProperties()
|
||||
# winprops.set_size(buff_size_x, buff_size_y)
|
||||
#
|
||||
#
|
||||
# props = FrameBufferProperties()
|
||||
# props.set_rgb_color(True)
|
||||
# props.set_rgba_bits(8, 8, 8, 8)
|
||||
# props.set_depth_bits(8)
|
||||
|
||||
# self.buff = self.graphicsEngine.make_output(
|
||||
# self.pipe, name, sort,
|
||||
# props, winprops,
|
||||
# GraphicsPipe.BF_resizeable,
|
||||
# self.win.get_gsg(), self.win)
|
||||
|
||||
#self.screenTexture = render_pipeline._final_stage.target.color_tex
|
||||
|
||||
#self.buff.addRenderTexture(self.screenTexture, GraphicsOutput.RTMCopyRam)
|
||||
# self.buff.set_sort(sort)
|
||||
|
||||
|
||||
|
||||
#self.cam = self.makeCamera(self.buff)
|
||||
#self.render_pipeline._showbase.cam=self.makeCamera(self.buff)
|
||||
|
||||
#self.render_pipeline._showbase.cam=self.makeCamera(self.buff)
|
||||
|
||||
#self.render_pipeline._showbase.camera.reparentTo(self.render)
|
||||
#base.camera.reparentTo(self.render)
|
||||
#self.cam.reparentTo(self.render) # 可选同步
|
||||
|
||||
#render_pipeline.set_camera(self.cam)
|
||||
|
||||
#添加渲染效果
|
||||
#self.cam = self.render_pipeline._showbase.cam
|
||||
#self.camNode = self.cam.node()
|
||||
#self.camLens = self.camNode.get_lens()
|
||||
self.render_pipeline._showbase.camera = self.render_pipeline._showbase.cam
|
||||
#self.render_pipeline.daytime_mgr.update()
|
||||
|
||||
|
||||
# if clear_color is None:
|
||||
# self.buff.set_clear_active(GraphicsOutput.RTPColor, False)
|
||||
# else:
|
||||
# self.buff.set_clear_color(clear_color)
|
||||
# self.buff.set_clear_active(GraphicsOutput.RTPColor, True)
|
||||
|
||||
# self.disableMouse()
|
||||
self.mouse_controller = CustomMouseController(self)
|
||||
self.mouse_controller.setUp()
|
||||
|
||||
# 添加错误处理钩子
|
||||
self.accept("transform_state_error", self._handle_transform_error)
|
||||
|
||||
def _handle_transform_error(self):
|
||||
"""处理TransformState相关的错误"""
|
||||
try:
|
||||
from panda3d.core import TransformState, RenderState
|
||||
TransformState.clear_cache()
|
||||
RenderState.clear_cache()
|
||||
print("已清理TransformState和RenderState缓存")
|
||||
except Exception as e:
|
||||
print(f"清理缓存时出错: {e}")
|
||||
|
||||
def render_pipeline(self):
|
||||
"""获取 RenderPipeline 实例"""
|
||||
return self._render_pipeline
|
||||
|
||||
|
||||
def set_parent(self, parent: QWidget):
|
||||
self.parent = parent
|
||||
self.mouseWatcherNode = QMouseWatcherNode(parent)
|
||||
|
||||
def getAspectRatio(self, win = None):
|
||||
if win is None and self.parent is not None:
|
||||
return float(self.parent.width()) / float(self.parent.height())
|
||||
else:
|
||||
return super().getAspectRatio(win)
|
||||
|
||||
def get_render_pipeline():
|
||||
"""获取全局 RenderPipeline 单例"""
|
||||
if _global_render_pipeline is None:
|
||||
raise RuntimeError(
|
||||
"RenderPipeline has not been initialized yet. Please create a 3DWorld instance first.")
|
||||
return _global_render_pipeline
|
||||
|
||||
def resize_buffer(self, width: int, height: int):
|
||||
props = WindowProperties()
|
||||
props.set_size(width, height)
|
||||
self.win.request_properties(props)
|
||||
|
||||
# 重新分配输出贴图的大小
|
||||
self.qt_output_tex.set_x_size(width)
|
||||
self.qt_output_tex.set_y_size(height)
|
||||
|
||||
# 更新 lens 的 aspect ratio
|
||||
if self.camLens:
|
||||
self.camLens.set_film_size(width, height) # 或 set_aspect_ratio(width / height)
|
||||
|
||||
# 强制更新窗口(有时在 Qt 内嵌时需要)
|
||||
self.graphicsEngine.open_windows()
|
||||
@ -1,355 +1,252 @@
|
||||
# -*- coding: utf-8-*-
|
||||
"""
|
||||
Module : QPanda3DWidget
|
||||
Author : Saifeddine ALOUI
|
||||
Description :
|
||||
This is the QWidget to be inserted in your standard PyQt5 application.
|
||||
It takes a Panda3DWorld object at init time.
|
||||
You should first create the Panda3DWorkd object before creating this widget.
|
||||
"""
|
||||
# PyQt imports
|
||||
from PyQt5 import QtWidgets, QtGui
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
|
||||
# Panda imports
|
||||
from panda3d.core import Texture, WindowProperties, CallbackGraphicsWindow
|
||||
from panda3d.core import loadPrcFileData
|
||||
|
||||
from QPanda3D.QPanda3D_Buttons_Translation import QPanda3D_Button_translation
|
||||
from QPanda3D.QPanda3D_Keys_Translation import QPanda3D_Key_translation
|
||||
from QPanda3D.QPanda3D_Modifiers_Translation import QPanda3D_Modifier_translation
|
||||
|
||||
__all__ = ["QPanda3DWidget"]
|
||||
|
||||
|
||||
class QPanda3DSynchronizer(QTimer):
|
||||
def __init__(self, qPanda3DWidget, FPS=60):
|
||||
QTimer.__init__(self)
|
||||
self.qPanda3DWidget = qPanda3DWidget
|
||||
dt = 1000 / FPS
|
||||
self.setInterval(int(dt))
|
||||
self.timeout.connect(self.tick)
|
||||
|
||||
def tick(self):
|
||||
try:
|
||||
# 在渲染前清理可能损坏的TransformState对象
|
||||
from panda3d.core import TransformState
|
||||
TransformState.clear_cache()
|
||||
|
||||
taskMgr.step()
|
||||
self.qPanda3DWidget.update()
|
||||
except AssertionError as e:
|
||||
# 专门处理 TransformState has_mat() 断言错误
|
||||
if "has_mat" in str(e):
|
||||
print(f"警告: 检测到TransformState断言错误,已静默处理: {e}")
|
||||
# 尝试恢复渲染状态
|
||||
try:
|
||||
# 强制清理缓存并重试
|
||||
from panda3d.core import TransformState, RenderState
|
||||
TransformState.clear_cache()
|
||||
RenderState.clear_cache()
|
||||
taskMgr.step()
|
||||
self.qPanda3DWidget.update()
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
# 重新抛出其他断言错误
|
||||
raise
|
||||
except Exception as e:
|
||||
# 静默处理其他所有异常
|
||||
print(f"警告: 检测到异常,已静默处理: {e}")
|
||||
|
||||
|
||||
def get_panda_key_modifiers(evt):
|
||||
panda_mods = []
|
||||
qt_mods = evt.modifiers()
|
||||
for qt_mod, panda_mod in QPanda3D_Modifier_translation.items():
|
||||
if (qt_mods & qt_mod) == qt_mod:
|
||||
panda_mods.append(panda_mod)
|
||||
return panda_mods
|
||||
|
||||
|
||||
def get_panda_key_modifiers_prefix(evt):
|
||||
# join all modifiers (except NoModifier, which is None) with '-'
|
||||
prefix = "-".join([mod for mod in get_panda_key_modifiers(evt) if mod is not None])
|
||||
|
||||
# if the prefix is not empty, append a '-'
|
||||
if prefix:
|
||||
prefix += '-'
|
||||
|
||||
return prefix
|
||||
|
||||
|
||||
class QPanda3DWidget(QWidget):
|
||||
"""
|
||||
An interactive panda3D QWidget
|
||||
Parent : Parent QT Widget
|
||||
FPS : Number of frames per socond to refresh the screen
|
||||
debug: Switch printing key events to console on/off
|
||||
"""
|
||||
|
||||
def __init__(self, panda3DWorld, parent=None, FPS=60, debug=False):
|
||||
QWidget.__init__(self, parent)
|
||||
self.rp_sync_requested = False
|
||||
# set fixed geometry
|
||||
self.panda3DWorld = panda3DWorld
|
||||
self.panda3DWorld.set_parent(self)
|
||||
# Setup a timer in Qt that runs taskMgr.step() to simulate Panda's own main loop
|
||||
# pandaTimer = QTimer(self)
|
||||
# pandaTimer.timeout.connect()
|
||||
# pandaTimer.start(0)
|
||||
|
||||
self.setFocusPolicy(Qt.StrongFocus)
|
||||
|
||||
# Setup another timer that redraws this widget in a specific FPS
|
||||
# redrawTimer = QTimer(self)
|
||||
# redrawTimer.timeout.connect(self.update)
|
||||
# redrawTimer.start(1000/FPS)
|
||||
|
||||
self.paintSurface = QPainter()
|
||||
self.rotate = QTransform()
|
||||
self.rotate.rotate(180)
|
||||
self.out_image = QImage()
|
||||
|
||||
size = self.panda3DWorld.cam.node().get_lens().get_film_size()
|
||||
self.initial_film_size = QSizeF(size.x, size.y)
|
||||
self.initial_size = self.size()
|
||||
|
||||
self.synchronizer = QPanda3DSynchronizer(self, FPS)
|
||||
self.synchronizer.start()
|
||||
|
||||
self.debug = debug
|
||||
|
||||
def mousePressEvent(self, evt):
|
||||
button = evt.button()
|
||||
try:
|
||||
b = "{}{}".format(get_panda_key_modifiers_prefix(evt), QPanda3D_Button_translation[button])
|
||||
if self.debug:
|
||||
print(b)
|
||||
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
|
||||
except:
|
||||
print("Unimplemented button. Please send an issue on github to fix this problem")
|
||||
|
||||
def mouseMoveEvent(self, evt:QtGui.QMouseEvent):
|
||||
button = evt.button()
|
||||
try:
|
||||
b = "mouse-move"
|
||||
if self.debug:
|
||||
print(b)
|
||||
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
|
||||
except:
|
||||
print("Unimplemented button. Please send an issue on github to fix this problem")
|
||||
|
||||
|
||||
def mouseReleaseEvent(self, evt):
|
||||
button = evt.button()
|
||||
try:
|
||||
b = "{}{}-up".format(get_panda_key_modifiers_prefix(evt), QPanda3D_Button_translation[button])
|
||||
if self.debug:
|
||||
print(b)
|
||||
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
|
||||
except:
|
||||
print("Unimplemented button. Please send an issue on github to fix this problem")
|
||||
|
||||
def wheelEvent(self, evt):
|
||||
delta = evt.angleDelta().y()
|
||||
try:
|
||||
if self.debug:
|
||||
print(f"wheel {delta}")
|
||||
messenger.send('wheel',[{"delta":delta}])
|
||||
except:
|
||||
print("Unimplemented button. Please send an issue on github to fix this problem")
|
||||
|
||||
def keyPressEvent(self, evt):
|
||||
key = evt.key()
|
||||
try:
|
||||
k = "{}{}".format(get_panda_key_modifiers_prefix(evt), QPanda3D_Key_translation[key])
|
||||
if self.debug:
|
||||
print(k)
|
||||
messenger.send(k)
|
||||
except:
|
||||
print("Unimplemented key. Please send an issue on github to fix this problem")
|
||||
|
||||
def keyReleaseEvent(self, evt):
|
||||
key = evt.key()
|
||||
try:
|
||||
k = "{}{}-up".format(get_panda_key_modifiers_prefix(evt), QPanda3D_Key_translation[key])
|
||||
if self.debug:
|
||||
print(k)
|
||||
messenger.send(k)
|
||||
except:
|
||||
print("Unimplemented key. Please send an issue on github to fix this problem")
|
||||
|
||||
def resizeEvent(self, evt):
|
||||
width = evt.size().width()
|
||||
height = evt.size().height()
|
||||
#print(f"width:{width}")
|
||||
#print(f"height:{height}")
|
||||
|
||||
from Panda3DWorld import resize_buffer
|
||||
#resize_buffer(width, height)
|
||||
|
||||
lens = self.panda3DWorld.cam.node().get_lens()
|
||||
# lens.set_film_size(self.initial_film_size.width() * evt.size().width() / self.initial_size.width(),
|
||||
# self.initial_film_size.height() * evt.size().height() / self.initial_size.height())
|
||||
#self.sync_panda3d_window_size(width, height)
|
||||
|
||||
#self.panda3DWorld.buff.setSize(evt.size().width(), evt.size().height())
|
||||
|
||||
def minimumSizeHint(self):
|
||||
return QSize(400, 300)
|
||||
|
||||
# Use the paint event to pull the contents of the panda texture to the widget
|
||||
# def paintEvent(self, event):
|
||||
# if self.panda3DWorld.screenTexture.mightHaveRamImage():
|
||||
# tex = self.panda3DWorld.screenTexture
|
||||
# gsg = base.win.getGsg()
|
||||
# #self.panda3DWorld.screenTexture.store(gsg)
|
||||
# base.graphicsEngine.extractTextureData(tex, gsg)
|
||||
# self.panda3DWorld.screenTexture.setFormat(Texture.FRgba32)
|
||||
# data = self.panda3DWorld.screenTexture.getRamImage().getData()
|
||||
# img = QImage(data, self.panda3DWorld.screenTexture.getXSize(), self.panda3DWorld.screenTexture.getYSize(),
|
||||
# QImage.Format_ARGB32).mirrored()
|
||||
# self.paintSurface.begin(self)
|
||||
# self.paintSurface.drawImage(0, 0, img)
|
||||
# self.paintSurface.end()
|
||||
|
||||
# def paintEvent(self, event):
|
||||
# tex = self.panda3DWorld.qt_output_tex
|
||||
#
|
||||
# gsg = base.win.getGsg()
|
||||
#
|
||||
#
|
||||
# if not self.rp_sync_requested:
|
||||
# base.graphicsEngine.extractTextureData(tex, gsg)
|
||||
# self.rp_sync_requested = True
|
||||
# self.update()
|
||||
# return
|
||||
#
|
||||
# if tex.hasRamImage():
|
||||
# data = tex.getRamImage().getData()
|
||||
# width = tex.getXSize()
|
||||
# height = tex.getYSize()
|
||||
#
|
||||
# # ✅ 应该 data 长度 = width * height * 4
|
||||
# img = QImage(data, width, height, QImage.Format_ARGB32).mirrored()
|
||||
#
|
||||
# painter = QPainter(self)
|
||||
# painter.drawImage(0, 0, img)
|
||||
# painter.end()
|
||||
#
|
||||
# self.rp_sync_requested = False
|
||||
# else:
|
||||
# print("⚠️ Texture has no RAM image yet, retrying next frame")
|
||||
# self.rp_sync_requested = False
|
||||
# self.update()
|
||||
|
||||
# def paintEvent(self, event):
|
||||
# tex = self.panda3DWorld.qt_output_tex
|
||||
#
|
||||
# gsg = base.win.getGsg()
|
||||
#
|
||||
# if not tex.hasRamImage():
|
||||
# base.graphicsEngine.extractTextureData(tex, gsg)
|
||||
# self.update() # 请求下一帧更新
|
||||
# return
|
||||
#
|
||||
# data = tex.getRamImage().getData()
|
||||
# width = tex.getXSize()
|
||||
# height = tex.getYSize()
|
||||
# expected_len = width * height * 4
|
||||
#
|
||||
# if len(data) != expected_len:
|
||||
# print(f"⚠️ 像素数据长度异常({len(data)} != {expected_len}),跳过绘制")
|
||||
# self.update()
|
||||
# return
|
||||
#
|
||||
# # 一切正常才绘制
|
||||
# img = QImage(data, width, height, QImage.Format_ARGB32).mirrored()
|
||||
#
|
||||
# painter = QPainter(self)
|
||||
# painter.drawImage(0, 0, img)
|
||||
# painter.end()
|
||||
|
||||
def paintEvent(self, event):
|
||||
tex = self.panda3DWorld.qt_output_tex
|
||||
gsg = base.win.getGsg()
|
||||
|
||||
if not gsg:
|
||||
self.update()
|
||||
return
|
||||
|
||||
if not tex.hasRamImage():
|
||||
base.graphicsEngine.extractTextureData(tex, gsg)
|
||||
self.update()
|
||||
return
|
||||
|
||||
data = tex.getRamImage().getData()
|
||||
tex_width = tex.getXSize()
|
||||
tex_height = tex.getYSize()
|
||||
expected_len = tex_width * tex_height * 4
|
||||
|
||||
if len(data) != expected_len:
|
||||
print(f"⚠️ 像素数据长度异常({len(data)} != {expected_len}),跳过绘制")
|
||||
self.update()
|
||||
return
|
||||
|
||||
img = QImage(data, tex_width, tex_height, QImage.Format_ARGB32).mirrored()
|
||||
|
||||
widget_width = self.width()
|
||||
widget_height = self.height()
|
||||
|
||||
painter = QPainter(self)
|
||||
|
||||
# 【保持宽高比的缩放】
|
||||
scaled_img = img.scaled(widget_width, widget_height, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||
|
||||
# 居中绘制
|
||||
x_offset = (widget_width - scaled_img.width()) // 2
|
||||
y_offset = (widget_height - scaled_img.height()) // 2
|
||||
|
||||
painter.drawImage(x_offset, y_offset, scaled_img)
|
||||
painter.end()
|
||||
|
||||
def sync_panda3d_window_size(self, width, height):
|
||||
"""同步 Panda3D 窗口尺寸到 Qt 窗口尺寸"""
|
||||
try:
|
||||
from panda3d.core import WindowProperties, LVecBase2i
|
||||
|
||||
# 确保尺寸是4的倍数(RenderPipeline 要求)
|
||||
adjusted_width = width - width % 4
|
||||
adjusted_height = height - height % 4
|
||||
|
||||
# 更新窗口属性
|
||||
props = WindowProperties()
|
||||
props.setSize(adjusted_width, adjusted_height)
|
||||
|
||||
# 对于 offscreen 渲染,直接更新窗口属性
|
||||
if self.panda3DWorld.win:
|
||||
self.panda3DWorld.win.request_properties(props)
|
||||
|
||||
# 手动触发 RenderPipeline 的尺寸更新逻辑
|
||||
if hasattr(self.panda3DWorld, 'render_pipeline'):
|
||||
# 更新全局分辨率
|
||||
from RenderPipelineFile.rpcore.globals import Globals
|
||||
Globals.native_resolution = LVecBase2i(adjusted_width, adjusted_height)
|
||||
|
||||
# 重新计算渲染分辨率
|
||||
self.panda3DWorld.render_pipeline._compute_render_resolution()
|
||||
|
||||
# 通知各个管理器处理尺寸变化
|
||||
self.panda3DWorld.render_pipeline.light_mgr.compute_tile_size()
|
||||
self.panda3DWorld.render_pipeline.stage_mgr.handle_window_resize()
|
||||
if hasattr(self.panda3DWorld.render_pipeline, 'debugger'):
|
||||
self.panda3DWorld.render_pipeline.debugger.handle_window_resize()
|
||||
|
||||
# 触发插件的窗口尺寸变化钩子
|
||||
self.panda3DWorld.render_pipeline.plugin_mgr.trigger_hook("window_resized")
|
||||
|
||||
print(f"Panda3D 窗口尺寸已同步为: {adjusted_width} x {adjusted_height}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"同步 Panda3D 窗口尺寸失败: {str(e)}")
|
||||
from PyQt5 import QtWidgets, QtGui
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
|
||||
from QMeta3D.QMeta3D_Buttons_Translation import QMeta3D_Button_translation
|
||||
from QMeta3D.QMeta3D_Keys_Translation import QMeta3D_Key_translation
|
||||
from QMeta3D.QMeta3D_Modifiers_Translation import QMeta3D_Modifier_translation
|
||||
|
||||
__all__ = ["QMeta3DWidget"]
|
||||
|
||||
|
||||
class QMeta3DSynchronizer(QTimer):
|
||||
def __init__(self, qMeta3DWidget, FPS=60):
|
||||
QTimer.__init__(self)
|
||||
self.qMeta3DWidget = qMeta3DWidget
|
||||
dt = 1000 / FPS
|
||||
self.setInterval(int(dt))
|
||||
self.timeout.connect(self.tick)
|
||||
|
||||
def tick(self):
|
||||
try:
|
||||
# 在渲染前清理可能损坏的TransformState对象
|
||||
from panda3d.core import TransformState
|
||||
TransformState.clear_cache()
|
||||
|
||||
taskMgr.step()
|
||||
self.qMeta3DWidget.update()
|
||||
except AssertionError as e:
|
||||
# 专门处理 TransformState has_mat() 断言错误
|
||||
if "has_mat" in str(e):
|
||||
print(f"警告: 检测到TransformState断言错误,已静默处理: {e}")
|
||||
# 尝试恢复渲染状态
|
||||
try:
|
||||
# 强制清理缓存并重试
|
||||
from panda3d.core import TransformState, RenderState
|
||||
TransformState.clear_cache()
|
||||
RenderState.clear_cache()
|
||||
taskMgr.step()
|
||||
self.qMeta3DWidget.update()
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
# 重新抛出其他断言错误
|
||||
raise
|
||||
except Exception as e:
|
||||
# 静默处理其他所有异常
|
||||
print(f"警告: 检测到异常,已静默处理: {e}")
|
||||
|
||||
|
||||
def get_panda_key_modifiers(evt):
|
||||
panda_mods = []
|
||||
qt_mods = evt.modifiers()
|
||||
for qt_mod, panda_mod in QMeta3D_Modifier_translation.items():
|
||||
if (qt_mods & qt_mod) == qt_mod:
|
||||
panda_mods.append(panda_mod)
|
||||
return panda_mods
|
||||
|
||||
|
||||
def get_panda_key_modifiers_prefix(evt):
|
||||
# join all modifiers (except NoModifier, which is None) with '-'
|
||||
prefix = "-".join([mod for mod in get_panda_key_modifiers(evt) if mod is not None])
|
||||
|
||||
# if the prefix is not empty, append a '-'
|
||||
if prefix:
|
||||
prefix += '-'
|
||||
|
||||
return prefix
|
||||
|
||||
|
||||
class QMeta3DWidget(QWidget):
|
||||
def __init__(self, Meta3DWorld, parent=None, FPS=60, debug=False):
|
||||
QWidget.__init__(self, parent)
|
||||
self.rp_sync_requested = False
|
||||
# set fixed geometry
|
||||
self.Meta3DWorld = Meta3DWorld
|
||||
self.Meta3DWorld.set_parent(self)
|
||||
# Setup a timer in Qt that runs taskMgr.step() to simulate Panda's own main loop
|
||||
# pandaTimer = QTimer(self)
|
||||
# pandaTimer.timeout.connect()
|
||||
# pandaTimer.start(0)
|
||||
|
||||
self.setFocusPolicy(Qt.StrongFocus)
|
||||
|
||||
# Setup another timer that redraws this widget in a specific FPS
|
||||
# redrawTimer = QTimer(self)
|
||||
# redrawTimer.timeout.connect(self.update)
|
||||
# redrawTimer.start(1000/FPS)
|
||||
|
||||
self.paintSurface = QPainter()
|
||||
self.rotate = QTransform()
|
||||
self.rotate.rotate(180)
|
||||
self.out_image = QImage()
|
||||
|
||||
size = self.Meta3DWorld.cam.node().get_lens().get_film_size()
|
||||
self.initial_film_size = QSizeF(size.x, size.y)
|
||||
self.initial_size = self.size()
|
||||
|
||||
self.synchronizer = QMeta3DSynchronizer(self, FPS)
|
||||
self.synchronizer.start()
|
||||
|
||||
self.debug = debug
|
||||
|
||||
def mousePressEvent(self, evt):
|
||||
button = evt.button()
|
||||
try:
|
||||
b = "{}{}".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Button_translation[button])
|
||||
if self.debug:
|
||||
print(b)
|
||||
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
|
||||
except:
|
||||
print("Unimplemented button. Please send an issue on github to fix this problem")
|
||||
|
||||
def mouseMoveEvent(self, evt:QtGui.QMouseEvent):
|
||||
button = evt.button()
|
||||
try:
|
||||
b = "mouse-move"
|
||||
if self.debug:
|
||||
print(b)
|
||||
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
|
||||
except:
|
||||
print("Unimplemented button. Please send an issue on github to fix this problem")
|
||||
|
||||
|
||||
def mouseReleaseEvent(self, evt):
|
||||
button = evt.button()
|
||||
try:
|
||||
b = "{}{}-up".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Button_translation[button])
|
||||
if self.debug:
|
||||
print(b)
|
||||
messenger.send(b,[{"x":evt.x(),"y":evt.y()}])
|
||||
except:
|
||||
print("Unimplemented button. Please send an issue on github to fix this problem")
|
||||
|
||||
def wheelEvent(self, evt):
|
||||
delta = evt.angleDelta().y()
|
||||
try:
|
||||
if self.debug:
|
||||
print(f"wheel {delta}")
|
||||
messenger.send('wheel',[{"delta":delta}])
|
||||
except:
|
||||
print("Unimplemented button. Please send an issue on github to fix this problem")
|
||||
|
||||
def keyPressEvent(self, evt):
|
||||
key = evt.key()
|
||||
try:
|
||||
k = "{}{}".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Key_translation[key])
|
||||
if self.debug:
|
||||
print(k)
|
||||
messenger.send(k)
|
||||
except:
|
||||
print("Unimplemented key. Please send an issue on github to fix this problem")
|
||||
|
||||
def keyReleaseEvent(self, evt):
|
||||
key = evt.key()
|
||||
try:
|
||||
k = "{}{}-up".format(get_panda_key_modifiers_prefix(evt), QMeta3D_Key_translation[key])
|
||||
if self.debug:
|
||||
print(k)
|
||||
messenger.send(k)
|
||||
except:
|
||||
print("Unimplemented key. Please send an issue on github to fix this problem")
|
||||
|
||||
def resizeEvent(self, evt):
|
||||
width = evt.size().width()
|
||||
height = evt.size().height()
|
||||
#print(f"width:{width}")
|
||||
#print(f"height:{height}")
|
||||
|
||||
from Meta3DWorld import resize_buffer
|
||||
|
||||
lens = self.Meta3DWorld.cam.node().get_lens()
|
||||
|
||||
def minimumSizeHint(self):
|
||||
return QSize(400, 300)
|
||||
|
||||
def paintEvent(self, event):
|
||||
tex = self.Meta3DWorld.qt_output_tex
|
||||
gsg = base.win.getGsg()
|
||||
|
||||
if not gsg:
|
||||
self.update()
|
||||
return
|
||||
|
||||
if not tex.hasRamImage():
|
||||
base.graphicsEngine.extractTextureData(tex, gsg)
|
||||
self.update()
|
||||
return
|
||||
|
||||
data = tex.getRamImage().getData()
|
||||
tex_width = tex.getXSize()
|
||||
tex_height = tex.getYSize()
|
||||
expected_len = tex_width * tex_height * 4
|
||||
|
||||
if len(data) != expected_len:
|
||||
print(f"⚠️ 像素数据长度异常({len(data)} != {expected_len}),跳过绘制")
|
||||
self.update()
|
||||
return
|
||||
|
||||
img = QImage(data, tex_width, tex_height, QImage.Format_ARGB32).mirrored()
|
||||
|
||||
widget_width = self.width()
|
||||
widget_height = self.height()
|
||||
|
||||
painter = QPainter(self)
|
||||
|
||||
# 【保持宽高比的缩放】
|
||||
scaled_img = img.scaled(widget_width, widget_height, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||
|
||||
# 居中绘制
|
||||
x_offset = (widget_width - scaled_img.width()) // 2
|
||||
y_offset = (widget_height - scaled_img.height()) // 2
|
||||
|
||||
painter.drawImage(x_offset, y_offset, scaled_img)
|
||||
painter.end()
|
||||
|
||||
def sync_Meta3d_window_size(self, width, height):
|
||||
try:
|
||||
from panda3d.core import WindowProperties, LVecBase2i
|
||||
|
||||
# 确保尺寸是4的倍数(RenderPipeline 要求)
|
||||
adjusted_width = width - width % 4
|
||||
adjusted_height = height - height % 4
|
||||
|
||||
# 更新窗口属性
|
||||
props = WindowProperties()
|
||||
props.setSize(adjusted_width, adjusted_height)
|
||||
|
||||
# 对于 offscreen 渲染,直接更新窗口属性
|
||||
if self.Meta3DWorld.win:
|
||||
self.Meta3DWorld.win.request_properties(props)
|
||||
|
||||
# 手动触发 RenderPipeline 的尺寸更新逻辑
|
||||
if hasattr(self.Meta3DWorld, 'render_pipeline'):
|
||||
# 更新全局分辨率
|
||||
from RenderPipelineFile.rpcore.globals import Globals
|
||||
Globals.native_resolution = LVecBase2i(adjusted_width, adjusted_height)
|
||||
|
||||
# 重新计算渲染分辨率
|
||||
self.Meta3DWorld.render_pipeline._compute_render_resolution()
|
||||
|
||||
# 通知各个管理器处理尺寸变化
|
||||
self.Meta3DWorld.render_pipeline.light_mgr.compute_tile_size()
|
||||
self.Meta3DWorld.render_pipeline.stage_mgr.handle_window_resize()
|
||||
if hasattr(self.Meta3DWorld.render_pipeline, 'debugger'):
|
||||
self.Meta3DWorld.render_pipeline.debugger.handle_window_resize()
|
||||
|
||||
# 触发插件的窗口尺寸变化钩子
|
||||
self.Meta3DWorld.render_pipeline.plugin_mgr.trigger_hook("window_resized")
|
||||
except Exception as e:
|
||||
print(f"同步 Meta3D 窗口尺寸失败: {str(e)}")
|
||||
@ -1,52 +1,43 @@
|
||||
# -*- coding: utf-8-*-
|
||||
"""
|
||||
Module : QPanda3D_Translation_Buttons
|
||||
Author : Niklas Mevenkamp
|
||||
Description :
|
||||
Contains a dictionary that translates QT mouse events to panda3d
|
||||
mouse events.
|
||||
"""
|
||||
# PyQt imports
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
import sys
|
||||
__all__ = ["QPanda3D_Keys_Translation"]
|
||||
|
||||
QPanda3D_Button_translation ={
|
||||
Qt.NoButton:'',
|
||||
Qt.AllButtons:'unknown',
|
||||
Qt.LeftButton:'mouse1',
|
||||
Qt.RightButton:'mouse2',
|
||||
Qt.MidButton:'mouse3',
|
||||
Qt.MiddleButton:'mouse3',
|
||||
Qt.BackButton:'unknown',
|
||||
Qt.XButton1:'unknown',
|
||||
Qt.ExtraButton1:'unknown',
|
||||
Qt.ForwardButton:'unknown',
|
||||
Qt.XButton2:'unknown',
|
||||
Qt.ExtraButton2:'unknown',
|
||||
Qt.TaskButton:'unknown',
|
||||
Qt.ExtraButton3:'unknown',
|
||||
Qt.ExtraButton4:'unknown',
|
||||
Qt.ExtraButton5:'unknown',
|
||||
Qt.ExtraButton6:'unknown',
|
||||
Qt.ExtraButton7:'unknown',
|
||||
Qt.ExtraButton8:'unknown',
|
||||
Qt.ExtraButton9:'unknown',
|
||||
Qt.ExtraButton10:'unknown',
|
||||
Qt.ExtraButton11:'unknown',
|
||||
Qt.ExtraButton12:'unknown',
|
||||
Qt.ExtraButton13:'unknown',
|
||||
Qt.ExtraButton14:'unknown',
|
||||
Qt.ExtraButton15:'unknown',
|
||||
Qt.ExtraButton16:'unknown',
|
||||
Qt.ExtraButton17:'unknown',
|
||||
Qt.ExtraButton18:'unknown',
|
||||
Qt.ExtraButton19:'unknown',
|
||||
Qt.ExtraButton20:'unknown',
|
||||
Qt.ExtraButton21:'unknown',
|
||||
Qt.ExtraButton22:'unknown',
|
||||
Qt.ExtraButton23:'unknown',
|
||||
Qt.ExtraButton24:'unknown',
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
import sys
|
||||
__all__ = ["QMeta3D_Keys_Translation.py"]
|
||||
|
||||
QMeta3D_Button_translation ={
|
||||
Qt.NoButton:'',
|
||||
Qt.AllButtons:'unknown',
|
||||
Qt.LeftButton:'mouse1',
|
||||
Qt.RightButton:'mouse2',
|
||||
Qt.MidButton:'mouse3',
|
||||
Qt.MiddleButton:'mouse3',
|
||||
Qt.BackButton:'unknown',
|
||||
Qt.XButton1:'unknown',
|
||||
Qt.ExtraButton1:'unknown',
|
||||
Qt.ForwardButton:'unknown',
|
||||
Qt.XButton2:'unknown',
|
||||
Qt.ExtraButton2:'unknown',
|
||||
Qt.TaskButton:'unknown',
|
||||
Qt.ExtraButton3:'unknown',
|
||||
Qt.ExtraButton4:'unknown',
|
||||
Qt.ExtraButton5:'unknown',
|
||||
Qt.ExtraButton6:'unknown',
|
||||
Qt.ExtraButton7:'unknown',
|
||||
Qt.ExtraButton8:'unknown',
|
||||
Qt.ExtraButton9:'unknown',
|
||||
Qt.ExtraButton10:'unknown',
|
||||
Qt.ExtraButton11:'unknown',
|
||||
Qt.ExtraButton12:'unknown',
|
||||
Qt.ExtraButton13:'unknown',
|
||||
Qt.ExtraButton14:'unknown',
|
||||
Qt.ExtraButton15:'unknown',
|
||||
Qt.ExtraButton16:'unknown',
|
||||
Qt.ExtraButton17:'unknown',
|
||||
Qt.ExtraButton18:'unknown',
|
||||
Qt.ExtraButton19:'unknown',
|
||||
Qt.ExtraButton20:'unknown',
|
||||
Qt.ExtraButton21:'unknown',
|
||||
Qt.ExtraButton22:'unknown',
|
||||
Qt.ExtraButton23:'unknown',
|
||||
Qt.ExtraButton24:'unknown',
|
||||
}
|
||||
@ -1,486 +1,477 @@
|
||||
# -*- coding: utf-8-*-
|
||||
"""
|
||||
Module : QPanda3D_Translation_Keys
|
||||
Author : Saifeddine ALOUI
|
||||
Description :
|
||||
Contains a dictionary that translates QT keyboard events to panda3d
|
||||
keyboard events.
|
||||
"""
|
||||
# PyQt imports
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
import sys
|
||||
__all__ = ["QPanda3D_Keys_Translation"]
|
||||
|
||||
QPanda3D_Key_translation ={
|
||||
Qt.Key_0:'0',
|
||||
Qt.Key_1:'1',
|
||||
Qt.Key_2:'2',
|
||||
Qt.Key_3:'3',
|
||||
Qt.Key_4:'4',
|
||||
Qt.Key_5:'5',
|
||||
Qt.Key_6:'6',
|
||||
Qt.Key_7:'7',
|
||||
Qt.Key_8:'8',
|
||||
Qt.Key_9:'9',
|
||||
Qt.Key_A:'a',
|
||||
Qt.Key_AE:'ae',
|
||||
Qt.Key_Aacute:'unknown',
|
||||
Qt.Key_Acircumflex:'unknown',
|
||||
Qt.Key_AddFavorite:'unknown',
|
||||
Qt.Key_Adiaeresis:'unknown',
|
||||
Qt.Key_Agrave:'unknown',
|
||||
Qt.Key_Alt:'lalt',
|
||||
Qt.Key_AltGr:'unknown',
|
||||
Qt.Key_Ampersand:'unknown',
|
||||
Qt.Key_Any:'unknown',
|
||||
Qt.Key_Apostrophe:'unknown',
|
||||
Qt.Key_ApplicationLeft:'unknown',
|
||||
Qt.Key_ApplicationRight:'unknown',
|
||||
Qt.Key_Aring:'unknown',
|
||||
Qt.Key_AsciiCircum:'unknown',
|
||||
Qt.Key_AsciiTilde:'unknown',
|
||||
Qt.Key_Asterisk:'unknown',
|
||||
Qt.Key_At:'unknown',
|
||||
Qt.Key_Atilde:'unknown',
|
||||
Qt.Key_AudioCycleTrack:'unknown',
|
||||
Qt.Key_AudioForward:'unknown',
|
||||
Qt.Key_AudioRandomPlay:'unknown',
|
||||
Qt.Key_AudioRepeat:'unknown',
|
||||
Qt.Key_AudioRewind:'unknown',
|
||||
Qt.Key_Away:'unknown',
|
||||
Qt.Key_B:'b',
|
||||
Qt.Key_Back:'unknown',
|
||||
Qt.Key_BackForward:'unknown',
|
||||
Qt.Key_Backslash:'unknown',
|
||||
Qt.Key_Backspace:'unknown',
|
||||
Qt.Key_Backtab:'unknown',
|
||||
Qt.Key_Bar:'unknown',
|
||||
Qt.Key_BassBoost:'unknown',
|
||||
Qt.Key_BassDown:'unknown',
|
||||
Qt.Key_BassUp:'unknown',
|
||||
Qt.Key_Battery:'unknown',
|
||||
Qt.Key_Blue:'unknown',
|
||||
Qt.Key_Bluetooth:'unknown',
|
||||
Qt.Key_Book:'unknown',
|
||||
Qt.Key_BraceLeft:'unknown',
|
||||
Qt.Key_BraceRight:'unknown',
|
||||
Qt.Key_BracketLeft:'unknown',
|
||||
Qt.Key_BracketRight:'unknown',
|
||||
Qt.Key_BrightnessAdjust:'unknown',
|
||||
Qt.Key_C:'c',
|
||||
Qt.Key_CD:'unknown',
|
||||
Qt.Key_Calculator:'unknown',
|
||||
Qt.Key_Calendar:'unknown',
|
||||
Qt.Key_Call:'unknown',
|
||||
Qt.Key_Camera:'unknown',
|
||||
Qt.Key_CameraFocus:'unknown',
|
||||
Qt.Key_Cancel:'unknown',
|
||||
Qt.Key_CapsLock:'unknown',
|
||||
Qt.Key_Ccedilla:'unknown',
|
||||
Qt.Key_ChannelDown:'unknown',
|
||||
Qt.Key_ChannelUp:'unknown',
|
||||
Qt.Key_Clear:'unknown',
|
||||
Qt.Key_ClearGrab:'unknown',
|
||||
Qt.Key_Close:'unknown',
|
||||
Qt.Key_Codeinput:'unknown',
|
||||
Qt.Key_Colon:'unknown',
|
||||
Qt.Key_Comma:'unknown',
|
||||
Qt.Key_Community:'unknown',
|
||||
Qt.Key_Context1:'unknown',
|
||||
Qt.Key_Context2:'unknown',
|
||||
Qt.Key_Context3:'unknown',
|
||||
Qt.Key_Context4:'unknown',
|
||||
Qt.Key_ContrastAdjust:'unknown',
|
||||
Qt.Key_Control:'control',
|
||||
Qt.Key_Copy:'unknown',
|
||||
Qt.Key_Cut:'unknown',
|
||||
Qt.Key_D:'d',
|
||||
Qt.Key_DOS:'unknown',
|
||||
Qt.Key_Dead_A:'unknown',
|
||||
Qt.Key_Dead_Abovecomma:'unknown',
|
||||
Qt.Key_Dead_Abovedot:'unknown',
|
||||
Qt.Key_Dead_Abovereversedcomma:'unknown',
|
||||
Qt.Key_Dead_Abovering:'unknown',
|
||||
Qt.Key_Dead_Aboveverticalline:'unknown',
|
||||
Qt.Key_Dead_Acute:'unknown',
|
||||
Qt.Key_Dead_Belowbreve:'unknown',
|
||||
Qt.Key_Dead_Belowcircumflex:'unknown',
|
||||
Qt.Key_Dead_Belowcomma:'unknown',
|
||||
Qt.Key_Dead_Belowdiaeresis:'unknown',
|
||||
Qt.Key_Dead_Belowdot:'unknown',
|
||||
Qt.Key_Dead_Belowmacron:'unknown',
|
||||
Qt.Key_Dead_Belowring:'unknown',
|
||||
Qt.Key_Dead_Belowtilde:'unknown',
|
||||
Qt.Key_Dead_Belowverticalline:'unknown',
|
||||
Qt.Key_Dead_Breve:'unknown',
|
||||
Qt.Key_Dead_Capital_Schwa:'unknown',
|
||||
Qt.Key_Dead_Caron:'unknown',
|
||||
Qt.Key_Dead_Cedilla:'unknown',
|
||||
Qt.Key_Dead_Circumflex:'unknown',
|
||||
Qt.Key_Dead_Currency:'unknown',
|
||||
Qt.Key_Dead_Diaeresis:'unknown',
|
||||
Qt.Key_Dead_Doubleacute:'unknown',
|
||||
Qt.Key_Dead_Doublegrave:'unknown',
|
||||
Qt.Key_Dead_E:'unknown',
|
||||
Qt.Key_Dead_Grave:'unknown',
|
||||
Qt.Key_Dead_Greek:'unknown',
|
||||
Qt.Key_Dead_Hook:'unknown',
|
||||
Qt.Key_Dead_Horn:'unknown',
|
||||
Qt.Key_Dead_I:'unknown',
|
||||
Qt.Key_Dead_Invertedbreve:'unknown',
|
||||
Qt.Key_Dead_Iota:'unknown',
|
||||
Qt.Key_Dead_Longsolidusoverlay:'unknown',
|
||||
Qt.Key_Dead_Lowline:'unknown',
|
||||
Qt.Key_Dead_Macron:'unknown',
|
||||
Qt.Key_Dead_O:'unknown',
|
||||
Qt.Key_Dead_Ogonek:'unknown',
|
||||
Qt.Key_Dead_Semivoiced_Sound:'unknown',
|
||||
Qt.Key_Dead_Small_Schwa:'unknown',
|
||||
Qt.Key_Dead_Stroke:'unknown',
|
||||
Qt.Key_Dead_Tilde:'unknown',
|
||||
Qt.Key_Dead_U:'unknown',
|
||||
Qt.Key_Dead_Voiced_Sound:'unknown',
|
||||
Qt.Key_Dead_a:'unknown',
|
||||
Qt.Key_Dead_e:'unknown',
|
||||
Qt.Key_Dead_i:'unknown',
|
||||
Qt.Key_Dead_o:'unknown',
|
||||
Qt.Key_Dead_u:'unknown',
|
||||
Qt.Key_Delete:'delete',
|
||||
Qt.Key_Direction_L:'unknown',
|
||||
Qt.Key_Direction_R:'unknown',
|
||||
Qt.Key_Display:'unknown',
|
||||
Qt.Key_Documents:'unknown',
|
||||
Qt.Key_Dollar:'unknown',
|
||||
Qt.Key_Down:'arrow_down',
|
||||
Qt.Key_E:'e',
|
||||
Qt.Key_ETH:'unknown',
|
||||
Qt.Key_Eacute:'unknown',
|
||||
Qt.Key_Ecircumflex:'unknown',
|
||||
Qt.Key_Ediaeresis:'unknown',
|
||||
Qt.Key_Egrave:'unknown',
|
||||
Qt.Key_Eisu_Shift:'unknown',
|
||||
Qt.Key_Eisu_toggle:'unknown',
|
||||
Qt.Key_Eject:'unknown',
|
||||
Qt.Key_End:'unknown',
|
||||
Qt.Key_Enter:'unknown',
|
||||
Qt.Key_Equal:'unknown',
|
||||
Qt.Key_Escape:'escape',
|
||||
Qt.Key_Excel:'unknown',
|
||||
Qt.Key_Exclam:'unknown',
|
||||
Qt.Key_Execute:'unknown',
|
||||
Qt.Key_Exit:'unknown',
|
||||
Qt.Key_Explorer:'unknown',
|
||||
Qt.Key_F:'f',
|
||||
Qt.Key_F1:'f1',
|
||||
Qt.Key_F10:'f10',
|
||||
Qt.Key_F11:'f11',
|
||||
Qt.Key_F12:'f12',
|
||||
Qt.Key_F13:'f13',
|
||||
Qt.Key_F14:'f14',
|
||||
Qt.Key_F15:'f15',
|
||||
Qt.Key_F16:'f16',
|
||||
Qt.Key_F17:'f17',
|
||||
Qt.Key_F18:'f18',
|
||||
Qt.Key_F19:'unknown',
|
||||
Qt.Key_F2:'unknown',
|
||||
Qt.Key_F20:'unknown',
|
||||
Qt.Key_F21:'unknown',
|
||||
Qt.Key_F22:'unknown',
|
||||
Qt.Key_F23:'unknown',
|
||||
Qt.Key_F24:'unknown',
|
||||
Qt.Key_F25:'unknown',
|
||||
Qt.Key_F26:'unknown',
|
||||
Qt.Key_F27:'unknown',
|
||||
Qt.Key_F28:'unknown',
|
||||
Qt.Key_F29:'unknown',
|
||||
Qt.Key_F3:'f3',
|
||||
Qt.Key_F30:'unknown',
|
||||
Qt.Key_F31:'unknown',
|
||||
Qt.Key_F32:'unknown',
|
||||
Qt.Key_F33:'unknown',
|
||||
Qt.Key_F34:'unknown',
|
||||
Qt.Key_F35:'unknown',
|
||||
Qt.Key_F4:'f4',
|
||||
Qt.Key_F5:'f5',
|
||||
Qt.Key_F6:'f6',
|
||||
Qt.Key_F7:'f7',
|
||||
Qt.Key_F8:'f8',
|
||||
Qt.Key_F9:'f9',
|
||||
Qt.Key_Favorites:'unknown',
|
||||
Qt.Key_Finance:'unknown',
|
||||
Qt.Key_Find:'unknown',
|
||||
Qt.Key_Flip:'unknown',
|
||||
Qt.Key_Forward:'unknown',
|
||||
Qt.Key_G:'g',
|
||||
Qt.Key_Game:'unknown',
|
||||
Qt.Key_Go:'unknown',
|
||||
Qt.Key_Greater:'unknown',
|
||||
Qt.Key_Green:'unknown',
|
||||
Qt.Key_Guide:'unknown',
|
||||
Qt.Key_H:'h',
|
||||
Qt.Key_Hangul:'unknown',
|
||||
Qt.Key_Hangul_Banja:'unknown',
|
||||
Qt.Key_Hangul_End:'unknown',
|
||||
Qt.Key_Hangul_Hanja:'unknown',
|
||||
Qt.Key_Hangul_Jamo:'unknown',
|
||||
Qt.Key_Hangul_Jeonja:'unknown',
|
||||
Qt.Key_Hangul_PostHanja:'unknown',
|
||||
Qt.Key_Hangul_PreHanja:'unknown',
|
||||
Qt.Key_Hangul_Romaja:'unknown',
|
||||
Qt.Key_Hangul_Special:'unknown',
|
||||
Qt.Key_Hangul_Start:'unknown',
|
||||
Qt.Key_Hangup:'unknown',
|
||||
Qt.Key_Hankaku:'unknown',
|
||||
Qt.Key_Help:'unknown',
|
||||
Qt.Key_Henkan:'unknown',
|
||||
Qt.Key_Hibernate:'unknown',
|
||||
Qt.Key_Hiragana:'unknown',
|
||||
Qt.Key_Hiragana_Katakana:'unknown',
|
||||
Qt.Key_History:'unknown',
|
||||
Qt.Key_Home:'home',
|
||||
Qt.Key_HomePage:'unknown',
|
||||
Qt.Key_HotLinks:'unknown',
|
||||
Qt.Key_Hyper_L:'unknown',
|
||||
Qt.Key_Hyper_R:'unknown',
|
||||
Qt.Key_I:'i',
|
||||
Qt.Key_Iacute:'unknown',
|
||||
Qt.Key_Icircumflex:'unknown',
|
||||
Qt.Key_Idiaeresis:'unknown',
|
||||
Qt.Key_Igrave:'unknown',
|
||||
Qt.Key_Info:'unknown',
|
||||
Qt.Key_Insert:'unknown',
|
||||
Qt.Key_J:'j',
|
||||
Qt.Key_K:'k',
|
||||
Qt.Key_Kana_Lock:'unknown',
|
||||
Qt.Key_Kana_Shift:'unknown',
|
||||
Qt.Key_Kanji:'unknown',
|
||||
Qt.Key_Katakana:'unknown',
|
||||
Qt.Key_KeyboardBrightnessDown:'unknown',
|
||||
Qt.Key_KeyboardBrightnessUp:'unknown',
|
||||
Qt.Key_KeyboardLightOnOff:'unknown',
|
||||
Qt.Key_L:'l',
|
||||
Qt.Key_LastNumberRedial:'unknown',
|
||||
Qt.Key_Launch0:'unknown',
|
||||
Qt.Key_Launch1:'unknown',
|
||||
Qt.Key_Launch2:'unknown',
|
||||
Qt.Key_Launch3:'unknown',
|
||||
Qt.Key_Launch4:'unknown',
|
||||
Qt.Key_Launch5:'unknown',
|
||||
Qt.Key_Launch6:'unknown',
|
||||
Qt.Key_Launch7:'unknown',
|
||||
Qt.Key_Launch8:'unknown',
|
||||
Qt.Key_Launch9:'unknown',
|
||||
Qt.Key_LaunchA:'unknown',
|
||||
Qt.Key_LaunchB:'unknown',
|
||||
Qt.Key_LaunchC:'unknown',
|
||||
Qt.Key_LaunchD:'unknown',
|
||||
Qt.Key_LaunchE:'unknown',
|
||||
Qt.Key_LaunchF:'unknown',
|
||||
Qt.Key_LaunchG:'unknown',
|
||||
Qt.Key_LaunchH:'unknown',
|
||||
Qt.Key_LaunchMail:'unknown',
|
||||
Qt.Key_LaunchMedia:'unknown',
|
||||
Qt.Key_Left:'arrow_left',
|
||||
Qt.Key_Less:'unknown',
|
||||
Qt.Key_LightBulb:'unknown',
|
||||
Qt.Key_LogOff:'unknown',
|
||||
Qt.Key_M:'m',
|
||||
Qt.Key_MailForward:'unknown',
|
||||
Qt.Key_Market:'unknown',
|
||||
Qt.Key_Massyo:'unknown',
|
||||
Qt.Key_MediaLast:'unknown',
|
||||
Qt.Key_MediaNext:'unknown',
|
||||
Qt.Key_MediaPause:'unknown',
|
||||
Qt.Key_MediaPlay:'unknown',
|
||||
Qt.Key_MediaPrevious:'unknown',
|
||||
Qt.Key_MediaRecord:'unknown',
|
||||
Qt.Key_MediaStop:'unknown',
|
||||
Qt.Key_MediaTogglePlayPause:'unknown',
|
||||
Qt.Key_Meeting:'unknown',
|
||||
Qt.Key_Memo:'unknown',
|
||||
Qt.Key_Menu:'unknown',
|
||||
Qt.Key_MenuKB:'unknown',
|
||||
Qt.Key_MenuPB:'unknown',
|
||||
Qt.Key_Messenger:'unknown',
|
||||
Qt.Key_Meta:'unknown',
|
||||
Qt.Key_MicMute:'unknown',
|
||||
Qt.Key_MicVolumeDown:'unknown',
|
||||
Qt.Key_MicVolumeUp:'unknown',
|
||||
Qt.Key_Minus:'unknown',
|
||||
Qt.Key_Mode_switch:'unknown',
|
||||
Qt.Key_MonBrightnessDown:'unknown',
|
||||
Qt.Key_MonBrightnessUp:'unknown',
|
||||
Qt.Key_Muhenkan:'unknown',
|
||||
Qt.Key_Multi_key:'unknown',
|
||||
Qt.Key_MultipleCandidate:'unknown',
|
||||
Qt.Key_Music:'unknown',
|
||||
Qt.Key_MySites:'unknown',
|
||||
Qt.Key_N:'n',
|
||||
Qt.Key_New:'unknown',
|
||||
Qt.Key_News:'unknown',
|
||||
Qt.Key_No:'unknown',
|
||||
Qt.Key_Ntilde:'unknown',
|
||||
Qt.Key_NumLock:'unknown',
|
||||
Qt.Key_NumberSign:'unknown',
|
||||
Qt.Key_O:'o',
|
||||
Qt.Key_Oacute:'unknown',
|
||||
Qt.Key_Ocircumflex:'unknown',
|
||||
Qt.Key_Odiaeresis:'unknown',
|
||||
Qt.Key_OfficeHome:'unknown',
|
||||
Qt.Key_Ograve:'unknown',
|
||||
Qt.Key_Ooblique:'unknown',
|
||||
Qt.Key_Open:'unknown',
|
||||
Qt.Key_OpenUrl:'unknown',
|
||||
Qt.Key_Option:'unknown',
|
||||
Qt.Key_Otilde:'unknown',
|
||||
Qt.Key_P:'p',
|
||||
Qt.Key_PageDown:'unknown',
|
||||
Qt.Key_PageUp:'unknown',
|
||||
Qt.Key_ParenLeft:'unknown',
|
||||
Qt.Key_ParenRight:'unknown',
|
||||
Qt.Key_Paste:'unknown',
|
||||
Qt.Key_Pause:'unknown',
|
||||
Qt.Key_Percent:'unknown',
|
||||
Qt.Key_Period:'unknown',
|
||||
Qt.Key_Phone:'unknown',
|
||||
Qt.Key_Pictures:'unknown',
|
||||
Qt.Key_Play:'unknown',
|
||||
Qt.Key_Plus:'unknown',
|
||||
Qt.Key_PowerDown:'unknown',
|
||||
Qt.Key_PowerOff:'unknown',
|
||||
Qt.Key_PreviousCandidate:'unknown',
|
||||
Qt.Key_Print:'unknown',
|
||||
Qt.Key_Printer:'unknown',
|
||||
Qt.Key_Q:'q',
|
||||
Qt.Key_Question:'unknown',
|
||||
Qt.Key_QuoteDbl:'unknown',
|
||||
Qt.Key_QuoteLeft:'unknown',
|
||||
Qt.Key_R:'r',
|
||||
Qt.Key_Red:'unknown',
|
||||
Qt.Key_Redo:'unknown',
|
||||
Qt.Key_Refresh:'unknown',
|
||||
Qt.Key_Reload:'unknown',
|
||||
Qt.Key_Reply:'unknown',
|
||||
Qt.Key_Return:'unknown',
|
||||
Qt.Key_Right:'arrow_right',
|
||||
Qt.Key_Romaji:'unknown',
|
||||
Qt.Key_RotateWindows:'unknown',
|
||||
Qt.Key_RotationKB:'unknown',
|
||||
Qt.Key_RotationPB:'unknown',
|
||||
Qt.Key_S:'s',
|
||||
Qt.Key_Save:'unknown',
|
||||
Qt.Key_ScreenSaver:'unknown',
|
||||
Qt.Key_ScrollLock:'unknown',
|
||||
Qt.Key_Search:'unknown',
|
||||
Qt.Key_Select:'unknown',
|
||||
Qt.Key_Semicolon:'unknown',
|
||||
Qt.Key_Send:'unknown',
|
||||
Qt.Key_Settings:'unknown',
|
||||
Qt.Key_Shift:'unknown',
|
||||
Qt.Key_Shop:'unknown',
|
||||
Qt.Key_SingleCandidate:'unknown',
|
||||
Qt.Key_Slash:'unknown',
|
||||
Qt.Key_Sleep:'unknown',
|
||||
Qt.Key_Space:'space',
|
||||
Qt.Key_Spell:'unknown',
|
||||
Qt.Key_SplitScreen:'unknown',
|
||||
Qt.Key_Standby:'unknown',
|
||||
Qt.Key_Stop:'unknown',
|
||||
Qt.Key_Subtitle:'unknown',
|
||||
Qt.Key_Super_L:'unknown',
|
||||
Qt.Key_Super_R:'unknown',
|
||||
Qt.Key_Support:'unknown',
|
||||
Qt.Key_Suspend:'unknown',
|
||||
Qt.Key_SysReq:'unknown',
|
||||
Qt.Key_T:'t',
|
||||
Qt.Key_THORN:'unknown',
|
||||
Qt.Key_Tab:'unknown',
|
||||
Qt.Key_TaskPane:'unknown',
|
||||
Qt.Key_Terminal:'unknown',
|
||||
Qt.Key_Time:'unknown',
|
||||
Qt.Key_ToDoList:'unknown',
|
||||
Qt.Key_ToggleCallHangup:'unknown',
|
||||
Qt.Key_Tools:'unknown',
|
||||
Qt.Key_TopMenu:'unknown',
|
||||
Qt.Key_TouchpadOff:'unknown',
|
||||
Qt.Key_TouchpadOn:'unknown',
|
||||
Qt.Key_TouchpadToggle:'unknown',
|
||||
Qt.Key_Touroku:'unknown',
|
||||
Qt.Key_Travel:'unknown',
|
||||
Qt.Key_TrebleDown:'unknown',
|
||||
Qt.Key_TrebleUp:'unknown',
|
||||
Qt.Key_U:'u',
|
||||
Qt.Key_UWB:'unknown',
|
||||
Qt.Key_Uacute:'unknown',
|
||||
Qt.Key_Ucircumflex:'unknown',
|
||||
Qt.Key_Udiaeresis:'unknown',
|
||||
Qt.Key_Ugrave:'unknown',
|
||||
Qt.Key_Underscore:'unknown',
|
||||
Qt.Key_Undo:'unknown',
|
||||
Qt.Key_Up:'arrow_up',
|
||||
Qt.Key_V:'v',
|
||||
Qt.Key_Video:'unknown',
|
||||
Qt.Key_View:'unknown',
|
||||
Qt.Key_VoiceDial:'unknown',
|
||||
Qt.Key_VolumeDown:'unknown',
|
||||
Qt.Key_VolumeMute:'unknown',
|
||||
Qt.Key_VolumeUp:'unknown',
|
||||
Qt.Key_W:'w',
|
||||
Qt.Key_WLAN:'unknown',
|
||||
Qt.Key_WWW:'unknown',
|
||||
Qt.Key_WakeUp:'unknown',
|
||||
Qt.Key_WebCam:'unknown',
|
||||
Qt.Key_Word:'unknown',
|
||||
Qt.Key_X:'x',
|
||||
Qt.Key_Xfer:'unknown',
|
||||
Qt.Key_Y:'y',
|
||||
Qt.Key_Yacute:'unknown',
|
||||
Qt.Key_Yellow:'unknown',
|
||||
Qt.Key_Yes:'unknown',
|
||||
Qt.Key_Z:'z',
|
||||
Qt.Key_Zenkaku:'unknown',
|
||||
Qt.Key_Zenkaku_Hankaku:'unknown',
|
||||
Qt.Key_Zoom:'unknown',
|
||||
Qt.Key_ZoomIn:'unknown',
|
||||
Qt.Key_ZoomOut:'unknown',
|
||||
Qt.Key_acute:'unknown',
|
||||
Qt.Key_brokenbar:'unknown',
|
||||
Qt.Key_cedilla:'unknown',
|
||||
Qt.Key_cent:'unknown',
|
||||
Qt.Key_copyright:'unknown',
|
||||
Qt.Key_currency:'unknown',
|
||||
Qt.Key_degree:'unknown',
|
||||
Qt.Key_diaeresis:'unknown',
|
||||
Qt.Key_division:'unknown',
|
||||
Qt.Key_exclamdown:'unknown',
|
||||
Qt.Key_guillemotleft:'unknown',
|
||||
Qt.Key_guillemotright:'unknown',
|
||||
Qt.Key_hyphen:'unknown',
|
||||
Qt.Key_iTouch:'unknown',
|
||||
Qt.Key_macron:'unknown',
|
||||
Qt.Key_masculine:'unknown',
|
||||
Qt.Key_mu:'unknown',
|
||||
Qt.Key_multiply:'unknown',
|
||||
Qt.Key_nobreakspace:'unknown',
|
||||
Qt.Key_notsign:'unknown',
|
||||
Qt.Key_onehalf:'unknown',
|
||||
Qt.Key_onequarter:'unknown',
|
||||
Qt.Key_onesuperior:'unknown',
|
||||
Qt.Key_ordfeminine:'unknown',
|
||||
Qt.Key_paragraph:'unknown',
|
||||
Qt.Key_periodcentered:'unknown',
|
||||
Qt.Key_plusminus:'unknown',
|
||||
Qt.Key_questiondown:'unknown',
|
||||
Qt.Key_registered:'unknown',
|
||||
Qt.Key_section:'unknown',
|
||||
Qt.Key_ssharp:'unknown',
|
||||
Qt.Key_sterling:'unknown',
|
||||
Qt.Key_threequarters:'unknown',
|
||||
Qt.Key_threesuperior:'unknown',
|
||||
Qt.Key_twosuperior:'unknown',
|
||||
Qt.Key_unknown:'unknown',
|
||||
Qt.Key_ydiaeresis:'unknown',
|
||||
Qt.Key_yen:'unknown',
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
import sys
|
||||
__all__ = ["QMeta3D_Keys_Translation.py"]
|
||||
|
||||
QMeta3D_Key_translation ={
|
||||
Qt.Key_0:'0',
|
||||
Qt.Key_1:'1',
|
||||
Qt.Key_2:'2',
|
||||
Qt.Key_3:'3',
|
||||
Qt.Key_4:'4',
|
||||
Qt.Key_5:'5',
|
||||
Qt.Key_6:'6',
|
||||
Qt.Key_7:'7',
|
||||
Qt.Key_8:'8',
|
||||
Qt.Key_9:'9',
|
||||
Qt.Key_A:'a',
|
||||
Qt.Key_AE:'ae',
|
||||
Qt.Key_Aacute:'unknown',
|
||||
Qt.Key_Acircumflex:'unknown',
|
||||
Qt.Key_AddFavorite:'unknown',
|
||||
Qt.Key_Adiaeresis:'unknown',
|
||||
Qt.Key_Agrave:'unknown',
|
||||
Qt.Key_Alt:'lalt',
|
||||
Qt.Key_AltGr:'unknown',
|
||||
Qt.Key_Ampersand:'unknown',
|
||||
Qt.Key_Any:'unknown',
|
||||
Qt.Key_Apostrophe:'unknown',
|
||||
Qt.Key_ApplicationLeft:'unknown',
|
||||
Qt.Key_ApplicationRight:'unknown',
|
||||
Qt.Key_Aring:'unknown',
|
||||
Qt.Key_AsciiCircum:'unknown',
|
||||
Qt.Key_AsciiTilde:'unknown',
|
||||
Qt.Key_Asterisk:'unknown',
|
||||
Qt.Key_At:'unknown',
|
||||
Qt.Key_Atilde:'unknown',
|
||||
Qt.Key_AudioCycleTrack:'unknown',
|
||||
Qt.Key_AudioForward:'unknown',
|
||||
Qt.Key_AudioRandomPlay:'unknown',
|
||||
Qt.Key_AudioRepeat:'unknown',
|
||||
Qt.Key_AudioRewind:'unknown',
|
||||
Qt.Key_Away:'unknown',
|
||||
Qt.Key_B:'b',
|
||||
Qt.Key_Back:'unknown',
|
||||
Qt.Key_BackForward:'unknown',
|
||||
Qt.Key_Backslash:'unknown',
|
||||
Qt.Key_Backspace:'unknown',
|
||||
Qt.Key_Backtab:'unknown',
|
||||
Qt.Key_Bar:'unknown',
|
||||
Qt.Key_BassBoost:'unknown',
|
||||
Qt.Key_BassDown:'unknown',
|
||||
Qt.Key_BassUp:'unknown',
|
||||
Qt.Key_Battery:'unknown',
|
||||
Qt.Key_Blue:'unknown',
|
||||
Qt.Key_Bluetooth:'unknown',
|
||||
Qt.Key_Book:'unknown',
|
||||
Qt.Key_BraceLeft:'unknown',
|
||||
Qt.Key_BraceRight:'unknown',
|
||||
Qt.Key_BracketLeft:'unknown',
|
||||
Qt.Key_BracketRight:'unknown',
|
||||
Qt.Key_BrightnessAdjust:'unknown',
|
||||
Qt.Key_C:'c',
|
||||
Qt.Key_CD:'unknown',
|
||||
Qt.Key_Calculator:'unknown',
|
||||
Qt.Key_Calendar:'unknown',
|
||||
Qt.Key_Call:'unknown',
|
||||
Qt.Key_Camera:'unknown',
|
||||
Qt.Key_CameraFocus:'unknown',
|
||||
Qt.Key_Cancel:'unknown',
|
||||
Qt.Key_CapsLock:'unknown',
|
||||
Qt.Key_Ccedilla:'unknown',
|
||||
Qt.Key_ChannelDown:'unknown',
|
||||
Qt.Key_ChannelUp:'unknown',
|
||||
Qt.Key_Clear:'unknown',
|
||||
Qt.Key_ClearGrab:'unknown',
|
||||
Qt.Key_Close:'unknown',
|
||||
Qt.Key_Codeinput:'unknown',
|
||||
Qt.Key_Colon:'unknown',
|
||||
Qt.Key_Comma:'unknown',
|
||||
Qt.Key_Community:'unknown',
|
||||
Qt.Key_Context1:'unknown',
|
||||
Qt.Key_Context2:'unknown',
|
||||
Qt.Key_Context3:'unknown',
|
||||
Qt.Key_Context4:'unknown',
|
||||
Qt.Key_ContrastAdjust:'unknown',
|
||||
Qt.Key_Control:'control',
|
||||
Qt.Key_Copy:'unknown',
|
||||
Qt.Key_Cut:'unknown',
|
||||
Qt.Key_D:'d',
|
||||
Qt.Key_DOS:'unknown',
|
||||
Qt.Key_Dead_A:'unknown',
|
||||
Qt.Key_Dead_Abovecomma:'unknown',
|
||||
Qt.Key_Dead_Abovedot:'unknown',
|
||||
Qt.Key_Dead_Abovereversedcomma:'unknown',
|
||||
Qt.Key_Dead_Abovering:'unknown',
|
||||
Qt.Key_Dead_Aboveverticalline:'unknown',
|
||||
Qt.Key_Dead_Acute:'unknown',
|
||||
Qt.Key_Dead_Belowbreve:'unknown',
|
||||
Qt.Key_Dead_Belowcircumflex:'unknown',
|
||||
Qt.Key_Dead_Belowcomma:'unknown',
|
||||
Qt.Key_Dead_Belowdiaeresis:'unknown',
|
||||
Qt.Key_Dead_Belowdot:'unknown',
|
||||
Qt.Key_Dead_Belowmacron:'unknown',
|
||||
Qt.Key_Dead_Belowring:'unknown',
|
||||
Qt.Key_Dead_Belowtilde:'unknown',
|
||||
Qt.Key_Dead_Belowverticalline:'unknown',
|
||||
Qt.Key_Dead_Breve:'unknown',
|
||||
Qt.Key_Dead_Capital_Schwa:'unknown',
|
||||
Qt.Key_Dead_Caron:'unknown',
|
||||
Qt.Key_Dead_Cedilla:'unknown',
|
||||
Qt.Key_Dead_Circumflex:'unknown',
|
||||
Qt.Key_Dead_Currency:'unknown',
|
||||
Qt.Key_Dead_Diaeresis:'unknown',
|
||||
Qt.Key_Dead_Doubleacute:'unknown',
|
||||
Qt.Key_Dead_Doublegrave:'unknown',
|
||||
Qt.Key_Dead_E:'unknown',
|
||||
Qt.Key_Dead_Grave:'unknown',
|
||||
Qt.Key_Dead_Greek:'unknown',
|
||||
Qt.Key_Dead_Hook:'unknown',
|
||||
Qt.Key_Dead_Horn:'unknown',
|
||||
Qt.Key_Dead_I:'unknown',
|
||||
Qt.Key_Dead_Invertedbreve:'unknown',
|
||||
Qt.Key_Dead_Iota:'unknown',
|
||||
Qt.Key_Dead_Longsolidusoverlay:'unknown',
|
||||
Qt.Key_Dead_Lowline:'unknown',
|
||||
Qt.Key_Dead_Macron:'unknown',
|
||||
Qt.Key_Dead_O:'unknown',
|
||||
Qt.Key_Dead_Ogonek:'unknown',
|
||||
Qt.Key_Dead_Semivoiced_Sound:'unknown',
|
||||
Qt.Key_Dead_Small_Schwa:'unknown',
|
||||
Qt.Key_Dead_Stroke:'unknown',
|
||||
Qt.Key_Dead_Tilde:'unknown',
|
||||
Qt.Key_Dead_U:'unknown',
|
||||
Qt.Key_Dead_Voiced_Sound:'unknown',
|
||||
Qt.Key_Dead_a:'unknown',
|
||||
Qt.Key_Dead_e:'unknown',
|
||||
Qt.Key_Dead_i:'unknown',
|
||||
Qt.Key_Dead_o:'unknown',
|
||||
Qt.Key_Dead_u:'unknown',
|
||||
Qt.Key_Delete:'delete',
|
||||
Qt.Key_Direction_L:'unknown',
|
||||
Qt.Key_Direction_R:'unknown',
|
||||
Qt.Key_Display:'unknown',
|
||||
Qt.Key_Documents:'unknown',
|
||||
Qt.Key_Dollar:'unknown',
|
||||
Qt.Key_Down:'arrow_down',
|
||||
Qt.Key_E:'e',
|
||||
Qt.Key_ETH:'unknown',
|
||||
Qt.Key_Eacute:'unknown',
|
||||
Qt.Key_Ecircumflex:'unknown',
|
||||
Qt.Key_Ediaeresis:'unknown',
|
||||
Qt.Key_Egrave:'unknown',
|
||||
Qt.Key_Eisu_Shift:'unknown',
|
||||
Qt.Key_Eisu_toggle:'unknown',
|
||||
Qt.Key_Eject:'unknown',
|
||||
Qt.Key_End:'unknown',
|
||||
Qt.Key_Enter:'unknown',
|
||||
Qt.Key_Equal:'unknown',
|
||||
Qt.Key_Escape:'escape',
|
||||
Qt.Key_Excel:'unknown',
|
||||
Qt.Key_Exclam:'unknown',
|
||||
Qt.Key_Execute:'unknown',
|
||||
Qt.Key_Exit:'unknown',
|
||||
Qt.Key_Explorer:'unknown',
|
||||
Qt.Key_F:'f',
|
||||
Qt.Key_F1:'f1',
|
||||
Qt.Key_F10:'f10',
|
||||
Qt.Key_F11:'f11',
|
||||
Qt.Key_F12:'f12',
|
||||
Qt.Key_F13:'f13',
|
||||
Qt.Key_F14:'f14',
|
||||
Qt.Key_F15:'f15',
|
||||
Qt.Key_F16:'f16',
|
||||
Qt.Key_F17:'f17',
|
||||
Qt.Key_F18:'f18',
|
||||
Qt.Key_F19:'unknown',
|
||||
Qt.Key_F2:'unknown',
|
||||
Qt.Key_F20:'unknown',
|
||||
Qt.Key_F21:'unknown',
|
||||
Qt.Key_F22:'unknown',
|
||||
Qt.Key_F23:'unknown',
|
||||
Qt.Key_F24:'unknown',
|
||||
Qt.Key_F25:'unknown',
|
||||
Qt.Key_F26:'unknown',
|
||||
Qt.Key_F27:'unknown',
|
||||
Qt.Key_F28:'unknown',
|
||||
Qt.Key_F29:'unknown',
|
||||
Qt.Key_F3:'f3',
|
||||
Qt.Key_F30:'unknown',
|
||||
Qt.Key_F31:'unknown',
|
||||
Qt.Key_F32:'unknown',
|
||||
Qt.Key_F33:'unknown',
|
||||
Qt.Key_F34:'unknown',
|
||||
Qt.Key_F35:'unknown',
|
||||
Qt.Key_F4:'f4',
|
||||
Qt.Key_F5:'f5',
|
||||
Qt.Key_F6:'f6',
|
||||
Qt.Key_F7:'f7',
|
||||
Qt.Key_F8:'f8',
|
||||
Qt.Key_F9:'f9',
|
||||
Qt.Key_Favorites:'unknown',
|
||||
Qt.Key_Finance:'unknown',
|
||||
Qt.Key_Find:'unknown',
|
||||
Qt.Key_Flip:'unknown',
|
||||
Qt.Key_Forward:'unknown',
|
||||
Qt.Key_G:'g',
|
||||
Qt.Key_Game:'unknown',
|
||||
Qt.Key_Go:'unknown',
|
||||
Qt.Key_Greater:'unknown',
|
||||
Qt.Key_Green:'unknown',
|
||||
Qt.Key_Guide:'unknown',
|
||||
Qt.Key_H:'h',
|
||||
Qt.Key_Hangul:'unknown',
|
||||
Qt.Key_Hangul_Banja:'unknown',
|
||||
Qt.Key_Hangul_End:'unknown',
|
||||
Qt.Key_Hangul_Hanja:'unknown',
|
||||
Qt.Key_Hangul_Jamo:'unknown',
|
||||
Qt.Key_Hangul_Jeonja:'unknown',
|
||||
Qt.Key_Hangul_PostHanja:'unknown',
|
||||
Qt.Key_Hangul_PreHanja:'unknown',
|
||||
Qt.Key_Hangul_Romaja:'unknown',
|
||||
Qt.Key_Hangul_Special:'unknown',
|
||||
Qt.Key_Hangul_Start:'unknown',
|
||||
Qt.Key_Hangup:'unknown',
|
||||
Qt.Key_Hankaku:'unknown',
|
||||
Qt.Key_Help:'unknown',
|
||||
Qt.Key_Henkan:'unknown',
|
||||
Qt.Key_Hibernate:'unknown',
|
||||
Qt.Key_Hiragana:'unknown',
|
||||
Qt.Key_Hiragana_Katakana:'unknown',
|
||||
Qt.Key_History:'unknown',
|
||||
Qt.Key_Home:'home',
|
||||
Qt.Key_HomePage:'unknown',
|
||||
Qt.Key_HotLinks:'unknown',
|
||||
Qt.Key_Hyper_L:'unknown',
|
||||
Qt.Key_Hyper_R:'unknown',
|
||||
Qt.Key_I:'i',
|
||||
Qt.Key_Iacute:'unknown',
|
||||
Qt.Key_Icircumflex:'unknown',
|
||||
Qt.Key_Idiaeresis:'unknown',
|
||||
Qt.Key_Igrave:'unknown',
|
||||
Qt.Key_Info:'unknown',
|
||||
Qt.Key_Insert:'unknown',
|
||||
Qt.Key_J:'j',
|
||||
Qt.Key_K:'k',
|
||||
Qt.Key_Kana_Lock:'unknown',
|
||||
Qt.Key_Kana_Shift:'unknown',
|
||||
Qt.Key_Kanji:'unknown',
|
||||
Qt.Key_Katakana:'unknown',
|
||||
Qt.Key_KeyboardBrightnessDown:'unknown',
|
||||
Qt.Key_KeyboardBrightnessUp:'unknown',
|
||||
Qt.Key_KeyboardLightOnOff:'unknown',
|
||||
Qt.Key_L:'l',
|
||||
Qt.Key_LastNumberRedial:'unknown',
|
||||
Qt.Key_Launch0:'unknown',
|
||||
Qt.Key_Launch1:'unknown',
|
||||
Qt.Key_Launch2:'unknown',
|
||||
Qt.Key_Launch3:'unknown',
|
||||
Qt.Key_Launch4:'unknown',
|
||||
Qt.Key_Launch5:'unknown',
|
||||
Qt.Key_Launch6:'unknown',
|
||||
Qt.Key_Launch7:'unknown',
|
||||
Qt.Key_Launch8:'unknown',
|
||||
Qt.Key_Launch9:'unknown',
|
||||
Qt.Key_LaunchA:'unknown',
|
||||
Qt.Key_LaunchB:'unknown',
|
||||
Qt.Key_LaunchC:'unknown',
|
||||
Qt.Key_LaunchD:'unknown',
|
||||
Qt.Key_LaunchE:'unknown',
|
||||
Qt.Key_LaunchF:'unknown',
|
||||
Qt.Key_LaunchG:'unknown',
|
||||
Qt.Key_LaunchH:'unknown',
|
||||
Qt.Key_LaunchMail:'unknown',
|
||||
Qt.Key_LaunchMedia:'unknown',
|
||||
Qt.Key_Left:'arrow_left',
|
||||
Qt.Key_Less:'unknown',
|
||||
Qt.Key_LightBulb:'unknown',
|
||||
Qt.Key_LogOff:'unknown',
|
||||
Qt.Key_M:'m',
|
||||
Qt.Key_MailForward:'unknown',
|
||||
Qt.Key_Market:'unknown',
|
||||
Qt.Key_Massyo:'unknown',
|
||||
Qt.Key_MediaLast:'unknown',
|
||||
Qt.Key_MediaNext:'unknown',
|
||||
Qt.Key_MediaPause:'unknown',
|
||||
Qt.Key_MediaPlay:'unknown',
|
||||
Qt.Key_MediaPrevious:'unknown',
|
||||
Qt.Key_MediaRecord:'unknown',
|
||||
Qt.Key_MediaStop:'unknown',
|
||||
Qt.Key_MediaTogglePlayPause:'unknown',
|
||||
Qt.Key_Meeting:'unknown',
|
||||
Qt.Key_Memo:'unknown',
|
||||
Qt.Key_Menu:'unknown',
|
||||
Qt.Key_MenuKB:'unknown',
|
||||
Qt.Key_MenuPB:'unknown',
|
||||
Qt.Key_Messenger:'unknown',
|
||||
Qt.Key_Meta:'unknown',
|
||||
Qt.Key_MicMute:'unknown',
|
||||
Qt.Key_MicVolumeDown:'unknown',
|
||||
Qt.Key_MicVolumeUp:'unknown',
|
||||
Qt.Key_Minus:'unknown',
|
||||
Qt.Key_Mode_switch:'unknown',
|
||||
Qt.Key_MonBrightnessDown:'unknown',
|
||||
Qt.Key_MonBrightnessUp:'unknown',
|
||||
Qt.Key_Muhenkan:'unknown',
|
||||
Qt.Key_Multi_key:'unknown',
|
||||
Qt.Key_MultipleCandidate:'unknown',
|
||||
Qt.Key_Music:'unknown',
|
||||
Qt.Key_MySites:'unknown',
|
||||
Qt.Key_N:'n',
|
||||
Qt.Key_New:'unknown',
|
||||
Qt.Key_News:'unknown',
|
||||
Qt.Key_No:'unknown',
|
||||
Qt.Key_Ntilde:'unknown',
|
||||
Qt.Key_NumLock:'unknown',
|
||||
Qt.Key_NumberSign:'unknown',
|
||||
Qt.Key_O:'o',
|
||||
Qt.Key_Oacute:'unknown',
|
||||
Qt.Key_Ocircumflex:'unknown',
|
||||
Qt.Key_Odiaeresis:'unknown',
|
||||
Qt.Key_OfficeHome:'unknown',
|
||||
Qt.Key_Ograve:'unknown',
|
||||
Qt.Key_Ooblique:'unknown',
|
||||
Qt.Key_Open:'unknown',
|
||||
Qt.Key_OpenUrl:'unknown',
|
||||
Qt.Key_Option:'unknown',
|
||||
Qt.Key_Otilde:'unknown',
|
||||
Qt.Key_P:'p',
|
||||
Qt.Key_PageDown:'unknown',
|
||||
Qt.Key_PageUp:'unknown',
|
||||
Qt.Key_ParenLeft:'unknown',
|
||||
Qt.Key_ParenRight:'unknown',
|
||||
Qt.Key_Paste:'unknown',
|
||||
Qt.Key_Pause:'unknown',
|
||||
Qt.Key_Percent:'unknown',
|
||||
Qt.Key_Period:'unknown',
|
||||
Qt.Key_Phone:'unknown',
|
||||
Qt.Key_Pictures:'unknown',
|
||||
Qt.Key_Play:'unknown',
|
||||
Qt.Key_Plus:'unknown',
|
||||
Qt.Key_PowerDown:'unknown',
|
||||
Qt.Key_PowerOff:'unknown',
|
||||
Qt.Key_PreviousCandidate:'unknown',
|
||||
Qt.Key_Print:'unknown',
|
||||
Qt.Key_Printer:'unknown',
|
||||
Qt.Key_Q:'q',
|
||||
Qt.Key_Question:'unknown',
|
||||
Qt.Key_QuoteDbl:'unknown',
|
||||
Qt.Key_QuoteLeft:'unknown',
|
||||
Qt.Key_R:'r',
|
||||
Qt.Key_Red:'unknown',
|
||||
Qt.Key_Redo:'unknown',
|
||||
Qt.Key_Refresh:'unknown',
|
||||
Qt.Key_Reload:'unknown',
|
||||
Qt.Key_Reply:'unknown',
|
||||
Qt.Key_Return:'unknown',
|
||||
Qt.Key_Right:'arrow_right',
|
||||
Qt.Key_Romaji:'unknown',
|
||||
Qt.Key_RotateWindows:'unknown',
|
||||
Qt.Key_RotationKB:'unknown',
|
||||
Qt.Key_RotationPB:'unknown',
|
||||
Qt.Key_S:'s',
|
||||
Qt.Key_Save:'unknown',
|
||||
Qt.Key_ScreenSaver:'unknown',
|
||||
Qt.Key_ScrollLock:'unknown',
|
||||
Qt.Key_Search:'unknown',
|
||||
Qt.Key_Select:'unknown',
|
||||
Qt.Key_Semicolon:'unknown',
|
||||
Qt.Key_Send:'unknown',
|
||||
Qt.Key_Settings:'unknown',
|
||||
Qt.Key_Shift:'unknown',
|
||||
Qt.Key_Shop:'unknown',
|
||||
Qt.Key_SingleCandidate:'unknown',
|
||||
Qt.Key_Slash:'unknown',
|
||||
Qt.Key_Sleep:'unknown',
|
||||
Qt.Key_Space:'space',
|
||||
Qt.Key_Spell:'unknown',
|
||||
Qt.Key_SplitScreen:'unknown',
|
||||
Qt.Key_Standby:'unknown',
|
||||
Qt.Key_Stop:'unknown',
|
||||
Qt.Key_Subtitle:'unknown',
|
||||
Qt.Key_Super_L:'unknown',
|
||||
Qt.Key_Super_R:'unknown',
|
||||
Qt.Key_Support:'unknown',
|
||||
Qt.Key_Suspend:'unknown',
|
||||
Qt.Key_SysReq:'unknown',
|
||||
Qt.Key_T:'t',
|
||||
Qt.Key_THORN:'unknown',
|
||||
Qt.Key_Tab:'unknown',
|
||||
Qt.Key_TaskPane:'unknown',
|
||||
Qt.Key_Terminal:'unknown',
|
||||
Qt.Key_Time:'unknown',
|
||||
Qt.Key_ToDoList:'unknown',
|
||||
Qt.Key_ToggleCallHangup:'unknown',
|
||||
Qt.Key_Tools:'unknown',
|
||||
Qt.Key_TopMenu:'unknown',
|
||||
Qt.Key_TouchpadOff:'unknown',
|
||||
Qt.Key_TouchpadOn:'unknown',
|
||||
Qt.Key_TouchpadToggle:'unknown',
|
||||
Qt.Key_Touroku:'unknown',
|
||||
Qt.Key_Travel:'unknown',
|
||||
Qt.Key_TrebleDown:'unknown',
|
||||
Qt.Key_TrebleUp:'unknown',
|
||||
Qt.Key_U:'u',
|
||||
Qt.Key_UWB:'unknown',
|
||||
Qt.Key_Uacute:'unknown',
|
||||
Qt.Key_Ucircumflex:'unknown',
|
||||
Qt.Key_Udiaeresis:'unknown',
|
||||
Qt.Key_Ugrave:'unknown',
|
||||
Qt.Key_Underscore:'unknown',
|
||||
Qt.Key_Undo:'unknown',
|
||||
Qt.Key_Up:'arrow_up',
|
||||
Qt.Key_V:'v',
|
||||
Qt.Key_Video:'unknown',
|
||||
Qt.Key_View:'unknown',
|
||||
Qt.Key_VoiceDial:'unknown',
|
||||
Qt.Key_VolumeDown:'unknown',
|
||||
Qt.Key_VolumeMute:'unknown',
|
||||
Qt.Key_VolumeUp:'unknown',
|
||||
Qt.Key_W:'w',
|
||||
Qt.Key_WLAN:'unknown',
|
||||
Qt.Key_WWW:'unknown',
|
||||
Qt.Key_WakeUp:'unknown',
|
||||
Qt.Key_WebCam:'unknown',
|
||||
Qt.Key_Word:'unknown',
|
||||
Qt.Key_X:'x',
|
||||
Qt.Key_Xfer:'unknown',
|
||||
Qt.Key_Y:'y',
|
||||
Qt.Key_Yacute:'unknown',
|
||||
Qt.Key_Yellow:'unknown',
|
||||
Qt.Key_Yes:'unknown',
|
||||
Qt.Key_Z:'z',
|
||||
Qt.Key_Zenkaku:'unknown',
|
||||
Qt.Key_Zenkaku_Hankaku:'unknown',
|
||||
Qt.Key_Zoom:'unknown',
|
||||
Qt.Key_ZoomIn:'unknown',
|
||||
Qt.Key_ZoomOut:'unknown',
|
||||
Qt.Key_acute:'unknown',
|
||||
Qt.Key_brokenbar:'unknown',
|
||||
Qt.Key_cedilla:'unknown',
|
||||
Qt.Key_cent:'unknown',
|
||||
Qt.Key_copyright:'unknown',
|
||||
Qt.Key_currency:'unknown',
|
||||
Qt.Key_degree:'unknown',
|
||||
Qt.Key_diaeresis:'unknown',
|
||||
Qt.Key_division:'unknown',
|
||||
Qt.Key_exclamdown:'unknown',
|
||||
Qt.Key_guillemotleft:'unknown',
|
||||
Qt.Key_guillemotright:'unknown',
|
||||
Qt.Key_hyphen:'unknown',
|
||||
Qt.Key_iTouch:'unknown',
|
||||
Qt.Key_macron:'unknown',
|
||||
Qt.Key_masculine:'unknown',
|
||||
Qt.Key_mu:'unknown',
|
||||
Qt.Key_multiply:'unknown',
|
||||
Qt.Key_nobreakspace:'unknown',
|
||||
Qt.Key_notsign:'unknown',
|
||||
Qt.Key_onehalf:'unknown',
|
||||
Qt.Key_onequarter:'unknown',
|
||||
Qt.Key_onesuperior:'unknown',
|
||||
Qt.Key_ordfeminine:'unknown',
|
||||
Qt.Key_paragraph:'unknown',
|
||||
Qt.Key_periodcentered:'unknown',
|
||||
Qt.Key_plusminus:'unknown',
|
||||
Qt.Key_questiondown:'unknown',
|
||||
Qt.Key_registered:'unknown',
|
||||
Qt.Key_section:'unknown',
|
||||
Qt.Key_ssharp:'unknown',
|
||||
Qt.Key_sterling:'unknown',
|
||||
Qt.Key_threequarters:'unknown',
|
||||
Qt.Key_threesuperior:'unknown',
|
||||
Qt.Key_twosuperior:'unknown',
|
||||
Qt.Key_unknown:'unknown',
|
||||
Qt.Key_ydiaeresis:'unknown',
|
||||
Qt.Key_yen:'unknown',
|
||||
}
|
||||
15
QMeta3D/QMeta3D_Modifiers_Translation.py
Normal file
15
QMeta3D/QMeta3D_Modifiers_Translation.py
Normal file
@ -0,0 +1,15 @@
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
import sys
|
||||
__all__ = ["QMeta3D_Modifiers_Translation.py"]
|
||||
|
||||
QMeta3D_Modifier_translation ={
|
||||
Qt.NoModifier:None,
|
||||
Qt.ShiftModifier:'shift',
|
||||
Qt.ControlModifier:'control',
|
||||
Qt.AltModifier:'alt',
|
||||
Qt.MetaModifier:'unknown',
|
||||
Qt.KeypadModifier:'unknown',
|
||||
Qt.GroupSwitchModifier:'unknown',
|
||||
}
|
||||
@ -1,41 +1,27 @@
|
||||
# -*- coding: utf-8-*-
|
||||
"""
|
||||
Module : QMouseWatcherNode
|
||||
Author : Niklas Mevenkamp
|
||||
Description :
|
||||
This is a MouseWatcherNode implementation that accesses
|
||||
mouse position and button states through a parent QWidget.
|
||||
"""
|
||||
|
||||
# PyQt imports
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
# Panda imports
|
||||
from panda3d.core import *
|
||||
|
||||
__all__ = ["QMouseWatcherNode"]
|
||||
|
||||
|
||||
class QMouseWatcherNode(MouseWatcher):
|
||||
def __init__(self, parent):
|
||||
super().__init__()
|
||||
|
||||
self.parent = parent
|
||||
|
||||
def getMouse(self, *args, **kwargs):
|
||||
# map global QCursor pixel position to parent Widget coordinates
|
||||
pos = self.parent.mapFromGlobal(QCursor.pos())
|
||||
|
||||
# map absolute pixel positions to relative ones
|
||||
rel_x = -1 + 2 * pos.x() / self.parent.width()
|
||||
rel_y = -1 + 2 * pos.y() / self.parent.height()
|
||||
|
||||
# invert y
|
||||
rel_y = -rel_y
|
||||
|
||||
return LPoint2(rel_x, rel_y)
|
||||
|
||||
def hasMouse(self):
|
||||
return isinstance(self.parent, QWidget)
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
from panda3d.core import *
|
||||
|
||||
__all__ = ["QMouseWatcherNode"]
|
||||
|
||||
|
||||
class QMouseWatcherNode(MouseWatcher):
|
||||
def __init__(self, parent):
|
||||
super().__init__()
|
||||
|
||||
self.parent = parent
|
||||
|
||||
def getMouse(self, *args, **kwargs):
|
||||
pos = self.parent.mapFromGlobal(QCursor.pos())
|
||||
|
||||
rel_x = -1 + 2 * pos.x() / self.parent.width()
|
||||
rel_y = -1 + 2 * pos.y() / self.parent.height()
|
||||
|
||||
rel_y = -rel_y
|
||||
|
||||
return LPoint2(rel_x, rel_y)
|
||||
|
||||
def hasMouse(self):
|
||||
return isinstance(self.parent, QWidget)
|
||||
@ -1,2 +1,2 @@
|
||||
name="QPanda3D"
|
||||
name="QMeta3D"
|
||||
__all__ = ["generate_qt_to_pd3d_translator"]
|
||||
11
QMeta3D/Tools/generate_qt_to_pd3d_translator.py
Normal file
11
QMeta3D/Tools/generate_qt_to_pd3d_translator.py
Normal file
@ -0,0 +1,11 @@
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
H=Qt.__dict__
|
||||
lst = [a for a in H if a.startswith("Key_")]
|
||||
QMeta3D_Key_translation = "QMeta3D_Key_translation ={"
|
||||
for i in range(len(lst)):
|
||||
QMeta3D_Key_translation += "Qt.{}:'unknown',\n".format(lst[i])
|
||||
QMeta3D_Key_translation += "}"
|
||||
print(QMeta3D_Key_translation)
|
||||
2
QMeta3D/__init__.py
Normal file
2
QMeta3D/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
name="QMeta3D"
|
||||
__all__ = ["QMeta3DWidget.py", "Meta3DWorld.py", "QMeta3D_Keys_Translation.py"]
|
||||
@ -1,24 +0,0 @@
|
||||
# -*- coding: utf-8-*-
|
||||
"""
|
||||
Module : QPanda3D_Translation_Modifiers
|
||||
Author : Niklas Mevenkamp
|
||||
Description :
|
||||
Contains a dictionary that translates QT keyboard events to panda3d
|
||||
keyboard events.
|
||||
"""
|
||||
# PyQt imports
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
import sys
|
||||
__all__ = ["QPanda3D_Modifiers_Translation"]
|
||||
|
||||
QPanda3D_Modifier_translation ={
|
||||
Qt.NoModifier:None,
|
||||
Qt.ShiftModifier:'shift',
|
||||
Qt.ControlModifier:'control',
|
||||
Qt.AltModifier:'alt',
|
||||
Qt.MetaModifier:'unknown',
|
||||
Qt.KeypadModifier:'unknown',
|
||||
Qt.GroupSwitchModifier:'unknown',
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
H=Qt.__dict__
|
||||
lst = [a for a in H if a.startswith("Key_")]
|
||||
QPanda3D_Key_translation ="QPanda3D_Key_translation ={"
|
||||
for i in range(len(lst)):
|
||||
QPanda3D_Key_translation +="Qt.{}:'unknown',\n".format(lst[i])
|
||||
QPanda3D_Key_translation += "}"
|
||||
print(QPanda3D_Key_translation)
|
||||
@ -1,2 +0,0 @@
|
||||
name="QPanda3D"
|
||||
__all__ = ["QPanda3DWidget", "Panda3DWorld", "QPanda3D_Keys_Translation"]
|
||||
File diff suppressed because one or more lines are too long
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
# This file stores internal settings of the pipeline. It does not contain the
|
||||
# plugin settings, but just the basic settings of the internal pipeline components.
|
||||
pipeline:
|
||||
@ -77,8 +75,8 @@ shadows:
|
||||
# getting updated fast enough. However, this also affects the performance
|
||||
# quite a bit, since for every shadow map a part of the scene has
|
||||
# to get re-rendered.
|
||||
max_updates: 8
|
||||
max_updates: 16
|
||||
|
||||
# Sets the maximum distance until which shadows are updated. If a shadow
|
||||
# source is further away, it will no longer recieve updates
|
||||
max_update_distance: 150.0
|
||||
max_update_distance: 300.0
|
||||
@ -16,16 +16,16 @@ enabled:
|
||||
- sky_ao
|
||||
- smaa
|
||||
- ssr
|
||||
# - clouds
|
||||
# - dof
|
||||
# - fxaa
|
||||
# - volumetrics
|
||||
# - vxgi
|
||||
- clouds
|
||||
#- dof
|
||||
#- fxaa
|
||||
#- volumetrics
|
||||
#- vxgi
|
||||
|
||||
|
||||
overrides:
|
||||
ao:
|
||||
blur_quality: MEDIUM
|
||||
blur_quality: LOW
|
||||
blur_normal_factor: 2.97
|
||||
blur_depth_factor: 0.88158
|
||||
occlusion_strength: 2.19
|
||||
@ -87,10 +87,10 @@ overrides:
|
||||
sharpen_twice: False
|
||||
|
||||
dof:
|
||||
focal_point: 1000.0
|
||||
focal_size: 994.0
|
||||
blur_strength: 0.0
|
||||
near_blur_strength: 0.4286
|
||||
focal_point: 5
|
||||
focal_size: 1
|
||||
blur_strength: 1
|
||||
near_blur_strength: 1
|
||||
|
||||
env_probes:
|
||||
probe_resolution: 128
|
||||
|
||||
@ -90,7 +90,6 @@ class LightManager(RPObject):
|
||||
|
||||
def remove_light(self, light):
|
||||
""" Removes a light """
|
||||
print(f'333333333333333333333333333333,{light.casts_shadows}')
|
||||
# from RenderPipelineFile.rpcore.pynative.internal_light_manager import InternalLightManager
|
||||
# inter = InternalLightManager()
|
||||
# inter.remove_light(light)
|
||||
|
||||
@ -142,7 +142,7 @@ class RenderPipeline(RPObject):
|
||||
if not isfile("/$$rp/data/install.flag"):
|
||||
self.fatal("You didn't setup the pipeline yet! Please run setup.py.")
|
||||
|
||||
load_prc_file("/$$rpconfig/panda3d-config.prc")
|
||||
load_prc_file("/$$rpconfig/Meta3d-config.prc")
|
||||
self._pre_showbase_initialized = True
|
||||
|
||||
def create(self, base=None):
|
||||
@ -208,7 +208,6 @@ class RenderPipeline(RPObject):
|
||||
def remove_light(self, light):
|
||||
""" Removes a previously attached light, check out the LightManager
|
||||
remove_light documentation for further information. """
|
||||
print(f'222222222222222222222222222,{light.casts_shadows}')
|
||||
self.light_mgr.remove_light(light)
|
||||
|
||||
def load_ies_profile(self, filename):
|
||||
|
||||
@ -1,29 +1,3 @@
|
||||
"""
|
||||
|
||||
RenderPipeline
|
||||
|
||||
Copyright (c) 2014-2016 tobspr <tobias.springer1@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from rpcore.render_stage import RenderStage
|
||||
|
||||
|
||||
|
||||
@ -1,29 +1,3 @@
|
||||
"""
|
||||
|
||||
RenderPipeline
|
||||
|
||||
Copyright (c) 2014-2016 tobspr <tobias.springer1@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
from rpcore.pluginbase.base_plugin import BasePlugin
|
||||
|
||||
from .dof_stage import DoFStage
|
||||
|
||||
@ -9,4 +9,5 @@ if not os.path.isfile(os.path.join(this_dir, "data", "install.flag")):
|
||||
print("Please install the pipeline first by running setup.py")
|
||||
sys.exit(-1)
|
||||
to_execute = os.path.join(this_dir, "toolkit", "plugin_configurator", "main.py")
|
||||
subprocess.call([sys.executable, to_execute])
|
||||
# 使用相对路径而不是绝对路径
|
||||
subprocess.call([sys.executable, to_execute], cwd=this_dir)
|
||||
@ -33,7 +33,9 @@ from six.moves import range # pylint: disable=import-error
|
||||
|
||||
import math
|
||||
|
||||
from RenderPipelineFile.rplibs.pyqt_imports import * # noqa
|
||||
# 修复导入路径问题
|
||||
from rplibs.pyqt_imports import * # noqa
|
||||
|
||||
|
||||
class CurveWidget(QWidget):
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
|
||||
RenderPipeline
|
||||
@ -40,8 +42,9 @@ os.chdir(os.path.join(os.path.dirname(os.path.realpath(__file__))))
|
||||
# Add the render pipeline to the path
|
||||
sys.path.insert(0, "../../")
|
||||
|
||||
from RenderPipelineFile.rplibs.six import iteritems # noqa
|
||||
from RenderPipelineFile.rplibs.pyqt_imports import * # noqa
|
||||
# 修复导入路径问题
|
||||
from rplibs.six import iteritems # noqa
|
||||
from rplibs.pyqt_imports import * # noqa
|
||||
|
||||
from curve_widget import CurveWidget # noqa
|
||||
|
||||
|
||||
@ -1,32 +1,4 @@
|
||||
"""
|
||||
|
||||
RenderPipeline
|
||||
|
||||
Copyright (c) 2014-2016 tobspr <tobias.springer1@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
# This tool offers an interface to configure the pipeline
|
||||
|
||||
from __future__ import print_function
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
@ -49,7 +21,39 @@ from rplibs.pyqt_imports import * #noqa
|
||||
# Load the generated UI Layout
|
||||
from ui.main_window_generated import Ui_MainWindow # noqa
|
||||
|
||||
from ui.widgets import UniversalMessageDialog
|
||||
# 创建一个简单的UniversalMessageDialog类,避免复杂的导入问题
|
||||
class UniversalMessageDialog(QDialog):
|
||||
@staticmethod
|
||||
def show_success(parent, title, message, show_cancel=True, confirm_text="确认"):
|
||||
msg_box = QMessageBox(QMessageBox.Information, title, message, QMessageBox.Ok, parent)
|
||||
if show_cancel:
|
||||
msg_box.addButton(QMessageBox.Cancel)
|
||||
msg_box.button(QMessageBox.Ok).setText(confirm_text)
|
||||
return msg_box.exec_()
|
||||
|
||||
@staticmethod
|
||||
def show_warning(parent, title, message, show_cancel=True, confirm_text="确认"):
|
||||
msg_box = QMessageBox(QMessageBox.Warning, title, message, QMessageBox.Ok, parent)
|
||||
if show_cancel:
|
||||
msg_box.addButton(QMessageBox.Cancel)
|
||||
msg_box.button(QMessageBox.Ok).setText(confirm_text)
|
||||
return msg_box.exec_()
|
||||
|
||||
@staticmethod
|
||||
def show_error(parent, title, message, show_cancel=True, confirm_text="确认"):
|
||||
msg_box = QMessageBox(QMessageBox.Critical, title, message, QMessageBox.Ok, parent)
|
||||
if show_cancel:
|
||||
msg_box.addButton(QMessageBox.Cancel)
|
||||
msg_box.button(QMessageBox.Ok).setText(confirm_text)
|
||||
return msg_box.exec_()
|
||||
|
||||
@staticmethod
|
||||
def show_info(parent, title, message, show_cancel=True, confirm_text="确认"):
|
||||
msg_box = QMessageBox(QMessageBox.Information, title, message, QMessageBox.Ok, parent)
|
||||
if show_cancel:
|
||||
msg_box.addButton(QMessageBox.Cancel)
|
||||
msg_box.button(QMessageBox.Ok).setText(confirm_text)
|
||||
return msg_box.exec_()
|
||||
|
||||
from rpcore.pluginbase.manager import PluginManager # noqa
|
||||
from rpcore.util.network_communication import NetworkCommunication # noqa
|
||||
@ -106,6 +110,15 @@ class PluginConfigurator(QMainWindow, Ui_MainWindow):
|
||||
|
||||
def closeEvent(self, event): # noqa
|
||||
event.accept()
|
||||
# 通知主程序配置可能已更改
|
||||
try:
|
||||
# 发送一个信号或者写入一个标记文件来通知主程序
|
||||
marker_file = "/tmp/rp_plugin_config_changed.flag"
|
||||
with open(marker_file, "w") as f:
|
||||
f.write("Plugin configuration may have changed")
|
||||
except Exception as e:
|
||||
print(f"无法创建配置更改标记文件: {e}")
|
||||
|
||||
import os
|
||||
os._exit(1)
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -5,6 +5,9 @@ import sys
|
||||
project_root = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, project_root)
|
||||
|
||||
# 设置工作目录为项目根目录
|
||||
os.chdir(project_root)
|
||||
|
||||
# 添加 RenderPipeline 到路径(注意路径名称应与实际目录一致)
|
||||
render_pipeline_path = os.path.join(project_root, "RenderPipeline")
|
||||
sys.path.insert(0, render_pipeline_path)
|
||||
|
||||
@ -422,22 +422,26 @@ class SelectionSystem:
|
||||
is_rotate_tool = self.world.tool_manager.isRotateTool() if self.world.tool_manager else False
|
||||
|
||||
import os
|
||||
from panda3d.core import getModelPath, Filename
|
||||
|
||||
# 获取项目根目录
|
||||
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# 确保core目录在模型搜索路径中
|
||||
model_path = getModelPath()
|
||||
core_dir = os.path.join(base_dir, "core")
|
||||
core_filename = Filename.from_os_specific(core_dir)
|
||||
if not model_path.findFile(core_filename):
|
||||
model_path.appendDirectory(core_filename)
|
||||
print(f"✓ 添加core目录到模型搜索路径: {core_dir}")
|
||||
|
||||
if is_scale_tool:
|
||||
model_paths = [
|
||||
os.path.join(base_dir,"core/UniformScaleHandle.fbx"),
|
||||
]
|
||||
model_filename = "core/UniformScaleHandle.fbx"
|
||||
elif is_rotate_tool:
|
||||
model_paths = [
|
||||
os.path.join(base_dir,"core/RotationHandleQuarter.fbx"),
|
||||
]
|
||||
model_filename = "core/RotationHandleQuarter.fbx"
|
||||
arrow_filename = "core/TranslateArrowHandle.fbx"
|
||||
else:
|
||||
model_paths = [
|
||||
os.path.join(base_dir, "core/TranslateArrowHandle.fbx"),
|
||||
]
|
||||
|
||||
arrow_path = os.path.join(base_dir, "core/TranslateArrowHandle.fbx")
|
||||
model_filename = "core/TranslateArrowHandle.fbx"
|
||||
|
||||
# model_paths = [
|
||||
# "core/TranslateArrowHandle.fbx",
|
||||
@ -445,18 +449,15 @@ class SelectionSystem:
|
||||
# ]
|
||||
gizmo_model = None
|
||||
gizmoRot_model = None
|
||||
for path in model_paths:
|
||||
try:
|
||||
if is_rotate_tool:
|
||||
gizmo_model = self.world.loader.loadModel(arrow_path)
|
||||
gizmoRot_model = self.world.loader.loadModel(path)
|
||||
else:
|
||||
gizmo_model = self.world.loader.loadModel(path)
|
||||
if gizmo_model:
|
||||
#print(f"成功加载模型: {path}")
|
||||
break
|
||||
except:
|
||||
continue
|
||||
try:
|
||||
if is_rotate_tool:
|
||||
gizmo_model = self.world.loader.loadModel(arrow_filename)
|
||||
gizmoRot_model = self.world.loader.loadModel(model_filename)
|
||||
else:
|
||||
gizmo_model = self.world.loader.loadModel(model_filename)
|
||||
except Exception as e:
|
||||
print(f"加载模型失败: {e}")
|
||||
return
|
||||
|
||||
x_rHandle = None
|
||||
y_rHandle = None
|
||||
@ -647,7 +648,7 @@ class SelectionSystem:
|
||||
|
||||
import time
|
||||
current_time = time.time()
|
||||
if current_time - self._last_gizmo_update < 0.05: # 每0.05秒更新一次
|
||||
if current_time - self._last_gizmo_update < 0.5: # 每0.05秒更新一次
|
||||
return task.cont
|
||||
self._last_gizmo_update = current_time
|
||||
|
||||
@ -1624,8 +1625,6 @@ class SelectionSystem:
|
||||
|
||||
# 应用新缩放值
|
||||
self.gizmoTarget.setScale(new_scale)
|
||||
# 安全地更新属性面板
|
||||
#self._safeUpdatePropertyPanel()
|
||||
self.world.property_panel.refreshModelValues(self.gizmoTarget)
|
||||
return
|
||||
elif is_rotate_tool:
|
||||
@ -1645,7 +1644,6 @@ class SelectionSystem:
|
||||
start_hpr.y + rotation_amount,
|
||||
start_hpr.z + rotation_amount)
|
||||
self.gizmoTarget.setHpr(new_hpr)
|
||||
#self._safeUpdatePropertyPanel()
|
||||
self.world.property_panel.refreshModelValues(self.gizmoTarget)
|
||||
return
|
||||
|
||||
@ -1810,7 +1808,6 @@ class SelectionSystem:
|
||||
|
||||
# 实时更新属性面板
|
||||
self.world.property_panel.refreshModelValues(self.gizmoTarget)
|
||||
#self._safeUpdatePropertyPanel()
|
||||
|
||||
# 每次拖拽都输出调试信息(但限制频率)
|
||||
if not hasattr(self, '_last_drag_debug_time'):
|
||||
@ -1844,39 +1841,6 @@ class SelectionSystem:
|
||||
except:
|
||||
return False
|
||||
|
||||
def _safeUpdatePropertyPanel(self):
|
||||
"""安全地更新属性面板"""
|
||||
try:
|
||||
# 检查属性面板是否存在且有效
|
||||
if (hasattr(self.world, 'property_panel') and
|
||||
self.world.property_panel is not None):
|
||||
|
||||
# 检查目标节点是否有效
|
||||
if (self.gizmoTarget is not None and
|
||||
not self.gizmoTarget.isEmpty()):
|
||||
|
||||
# 检查是否有refreshModelValues方法
|
||||
if hasattr(self.world.property_panel, 'refreshModelValues'):
|
||||
self.world.property_panel.refreshModelValues(self.gizmoTarget)
|
||||
# 如果是GUI元素,可能需要特殊的处理
|
||||
elif (hasattr(self.gizmoTarget, 'getTag') and
|
||||
self.gizmoTarget.getTag("is_gui_element") == "1" and
|
||||
hasattr(self.world.property_panel, 'updateGUIPropertyPanel')):
|
||||
# 对于GUI元素,可能需要重新构建整个面板
|
||||
if (hasattr(self.world, 'treeWidget') and
|
||||
self.world.treeWidget is not None):
|
||||
current_item = self.world.treeWidget.currentItem()
|
||||
if current_item is not None:
|
||||
self.world.property_panel.updatePropertyPanel(current_item)
|
||||
except RuntimeError as e:
|
||||
if "wrapped C/C++ object" in str(e):
|
||||
# 忽略控件已被删除的错误
|
||||
print("警告: 属性面板控件已被删除,跳过更新")
|
||||
else:
|
||||
print(f"更新属性面板时出错: {e}")
|
||||
except Exception as e:
|
||||
print(f"更新属性面板失败: {e}")
|
||||
|
||||
def stopGizmoDrag(self):
|
||||
"""停止坐标轴拖拽"""
|
||||
print(f"停止坐标轴拖拽 - 轴: {self.dragGizmoAxis}")
|
||||
|
||||
@ -11,5 +11,8 @@
|
||||
"enable_ssr": false,
|
||||
"shadow_quality": "medium",
|
||||
"ao_quality": "low"
|
||||
}
|
||||
},
|
||||
"anti_aliasing": "4x",
|
||||
"refresh_rate": "90Hz",
|
||||
"async_reprojection": true
|
||||
}
|
||||
129
core/world.py
129
core/world.py
@ -6,7 +6,7 @@ from direct.actor.Actor import Actor
|
||||
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
|
||||
from QPanda3D.Panda3DWorld import Panda3DWorld
|
||||
from QMeta3D.Meta3DWorld import Meta3DWorld
|
||||
from panda3d.core import (CardMaker, Vec4, Vec3, AmbientLight, DirectionalLight,
|
||||
Point3, WindowProperties,Material,LColor)
|
||||
from direct.showbase.ShowBaseGlobal import globalClock
|
||||
@ -20,7 +20,7 @@ except ImportError:
|
||||
PLUGIN_SUPPORT = False
|
||||
print("⚠ 插件管理器未找到,插件功能将不可用")
|
||||
|
||||
class CoreWorld(Panda3DWorld):
|
||||
class CoreWorld(Meta3DWorld):
|
||||
"""核心世界功能类 - 负责基础的3D世界设置和核心功能"""
|
||||
|
||||
def __init__(self):
|
||||
@ -77,6 +77,27 @@ class CoreWorld(Panda3DWorld):
|
||||
model_path.appendDirectory(resources_filename)
|
||||
print(f"✓ 添加Resources到模型搜索路径: {resources_dir}")
|
||||
|
||||
# 添加core目录到搜索路径
|
||||
core_dir = os.path.join(project_root, "core")
|
||||
core_filename = Filename.from_os_specific(core_dir)
|
||||
if not model_path.findFile(core_filename):
|
||||
model_path.appendDirectory(core_filename)
|
||||
print(f"✓ 添加core目录到模型搜索路径: {core_dir}")
|
||||
|
||||
# 添加RenderPipeline目录到搜索路径
|
||||
rp_dir = os.path.join(project_root, "RenderPipelineFile")
|
||||
rp_filename = Filename.from_os_specific(rp_dir)
|
||||
if not model_path.findFile(rp_filename):
|
||||
model_path.appendDirectory(rp_filename)
|
||||
print(f"✓ 添加RenderPipeline目录到模型搜索路径: {rp_dir}")
|
||||
|
||||
# 添加RenderPipeline data目录到搜索路径
|
||||
rp_data_dir = os.path.join(rp_dir, "data")
|
||||
rp_data_filename = Filename.from_os_specific(rp_data_dir)
|
||||
if not model_path.findFile(rp_data_filename):
|
||||
model_path.appendDirectory(rp_data_filename)
|
||||
print(f"✓ 添加RenderPipeline data目录到模型搜索路径: {rp_data_dir}")
|
||||
|
||||
# 同时添加各个子目录到搜索路径
|
||||
subdirs = ['models', 'textures', 'animations', 'icons', 'materials']
|
||||
for subdir in subdirs:
|
||||
@ -213,7 +234,6 @@ class CoreWorld(Panda3DWorld):
|
||||
temp_anim.removeNode() # 清理临时动画
|
||||
except Exception as e:
|
||||
print(f"❌ 动画文件加载失败: {e}")
|
||||
return None
|
||||
# 4. 尝试创建Actor
|
||||
print(f"4. Actor创建测试:")
|
||||
|
||||
@ -492,16 +512,105 @@ class CoreWorld(Panda3DWorld):
|
||||
|
||||
|
||||
|
||||
# def _loadFont(self):
|
||||
# """加载中文字体"""
|
||||
# try:
|
||||
# self.chinese_font = self.loader.loadFont('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc')
|
||||
# if not self.chinese_font:
|
||||
# print("警告: 无法加载中文字体,将使用默认字体")
|
||||
# else:
|
||||
# print("✓ 中文字体加载成功")
|
||||
# except:
|
||||
# print("警告: 无法加载中文字体,将使用默认字体")
|
||||
# self.chinese_font = None
|
||||
|
||||
def _loadFont(self):
|
||||
"""加载中文字体"""
|
||||
"""加载中文字体 - 跨平台,Panda3D 友好路径"""
|
||||
try:
|
||||
self.chinese_font = self.loader.loadFont('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc')
|
||||
import os
|
||||
import platform
|
||||
from pathlib import Path
|
||||
from panda3d.core import Filename
|
||||
|
||||
self.chinese_font = None # 初始化
|
||||
|
||||
# --- 平台与项目根 ---
|
||||
system = platform.system().lower()
|
||||
project_root = Path(__file__).resolve().parent.parent # 上两级
|
||||
|
||||
# --- 候选字体路径(按平台) ---
|
||||
if system == "windows":
|
||||
win_dir = os.environ.get("WINDIR") or r"C:\Windows"
|
||||
win_fonts_dir = Path(win_dir) / "Fonts"
|
||||
font_candidates = [
|
||||
project_root / "RenderPipelineFile" / "data" / "font" / "msyh.ttc",
|
||||
win_fonts_dir / "msyh.ttc",
|
||||
win_fonts_dir / "msyh.ttf",
|
||||
win_fonts_dir / "simhei.ttf",
|
||||
win_fonts_dir / "simsun.ttc",
|
||||
]
|
||||
elif system == "darwin": # macOS
|
||||
font_candidates = [
|
||||
Path("/System/Library/Fonts/PingFang.ttc"),
|
||||
Path("/System/Library/Fonts/STHeiti.ttc"),
|
||||
Path("/Library/Fonts/Songti.ttc"),
|
||||
]
|
||||
else: # Linux / 其他
|
||||
font_candidates = [
|
||||
Path("/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"),
|
||||
Path("/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc"),
|
||||
Path("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"),
|
||||
]
|
||||
|
||||
# --- 逐个尝试加载 ---
|
||||
for os_path in font_candidates:
|
||||
os_path_str = str(os_path)
|
||||
if not os.path.exists(os_path_str):
|
||||
# 文件确实不存在就跳过
|
||||
continue
|
||||
|
||||
# 1) 先把 OS 路径转换成 Panda 内部路径(/d/... 或 /usr/...)
|
||||
panda_fn = Filename.fromOsSpecific(os_path_str)
|
||||
panda_fn.makeTrueCase() # Windows 上修正大小写(更稳)
|
||||
panda_internal = panda_fn.getFullpath() # 取“内部样式”的字符串
|
||||
|
||||
# 2) 打印便于对照 Panda 的日志
|
||||
try:
|
||||
print(f"[FontLoader] 尝试加载: {panda_internal}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
# 3) 传“字符串”给 loader.loadFont(关键修复点)
|
||||
font = self.loader.loadFont(panda_internal)
|
||||
if font:
|
||||
self.chinese_font = font
|
||||
print("✓ 中文字体加载成功:", os_path_str)
|
||||
break
|
||||
else:
|
||||
print("[FontLoader] 返回空字体对象,继续尝试下一个候选...")
|
||||
except TypeError as te:
|
||||
# 某些旧版绑定只接受 str,不接受 Filename;此处已传 str,若仍报错再兜底一次
|
||||
try:
|
||||
font = self.loader.loadFont(str(panda_fn)) # 退一步:str(Filename)
|
||||
if font:
|
||||
self.chinese_font = font
|
||||
print("✓ 中文字体加载成功(备用API):", os_path_str)
|
||||
break
|
||||
else:
|
||||
print("[FontLoader] 备用API仍返回空字体对象,继续…")
|
||||
except Exception as te2:
|
||||
print(f"[FontLoader] 加载失败(TypeError),继续下一个: {os_path},原因: {te2}")
|
||||
except Exception as e:
|
||||
print(f"[FontLoader] 加载失败,继续下一个: {os_path},原因: {e}")
|
||||
|
||||
# --- 兜底 ---
|
||||
if not self.chinese_font:
|
||||
print("警告: 无法加载中文字体,将使用默认字体")
|
||||
else:
|
||||
print("✓ 中文字体加载成功")
|
||||
except:
|
||||
print("警告: 无法加载中文字体,将使用默认字体")
|
||||
print("警告: 无法加载中文字体,将使用默认字体(可能导致中文显示不全)")
|
||||
self.chinese_font = None
|
||||
|
||||
except Exception as e:
|
||||
print(f"警告: 加载中文字体时发生错误: {e}")
|
||||
self.chinese_font = None
|
||||
|
||||
def setQtWidget(self, widget):
|
||||
|
||||
@ -11,12 +11,12 @@ warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QLabel, QPushButton, QHBoxLayout
|
||||
from PyQt5.QtCore import Qt
|
||||
from QPanda3D.QPanda3DWidget import QPanda3DWidget
|
||||
from QPanda3D.Panda3DWorld import Panda3DWorld
|
||||
from QMeta3D.QMeta3DWidget import QMeta3DWidget
|
||||
from QMeta3D.Meta3DWorld import Meta3DWorld
|
||||
from panda3d.core import *
|
||||
from direct.task import Task
|
||||
|
||||
class GizmoDragTestWorld(Panda3DWorld):
|
||||
class GizmoDragTestWorld(Meta3DWorld):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@ -529,7 +529,7 @@ class GizmoDragTestWorld(Panda3DWorld):
|
||||
print(f"设置坐标轴颜色失败: {str(e)}")
|
||||
|
||||
|
||||
class CustomGizmoDragTestWidget(QPanda3DWidget):
|
||||
class CustomGizmoDragTestWidget(QMeta3DWidget):
|
||||
"""支持坐标轴拖拽测试的部件"""
|
||||
def __init__(self, world, parent=None):
|
||||
super().__init__(world, parent)
|
||||
|
||||
@ -16,15 +16,15 @@ from PyQt5.QtWidgets import (QApplication, QMainWindow, QMenuBar, QMenu, QAction
|
||||
QLabel, QLineEdit, QFormLayout, QDoubleSpinBox, QScrollArea, QTreeView, QInputDialog, QFileDialog, QMessageBox, QDialog, QGroupBox, QHBoxLayout, QPushButton, QDialogButtonBox)
|
||||
from PyQt5.QtCore import Qt, QDir, QUrl
|
||||
from PyQt5.QtGui import QDrag, QPainter, QPixmap
|
||||
from QPanda3D.QPanda3DWidget import QPanda3DWidget
|
||||
from QPanda3D.Panda3DWorld import Panda3DWorld
|
||||
from QMeta3D.QMeta3DWidget import QMeta3DWidget
|
||||
from QMeta3D.Meta3DWorld import Meta3DWorld
|
||||
from direct.gui.DirectGui import *
|
||||
from direct.gui.OnscreenText import OnscreenText
|
||||
from panda3d.core import *
|
||||
import os
|
||||
|
||||
# 简化的世界类,专门用于GUI测试
|
||||
class GUITestWorld(Panda3DWorld):
|
||||
class GUITestWorld(Meta3DWorld):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@ -270,7 +270,7 @@ class GUITestWorld(Panda3DWorld):
|
||||
"""GUI输入框提交事件处理"""
|
||||
print(f"✓ GUI输入框提交测试成功: {entry_id} = {text}")
|
||||
|
||||
class GUITestWidget(QPanda3DWidget):
|
||||
class GUITestWidget(QMeta3DWidget):
|
||||
def __init__(self, world, parent=None):
|
||||
super().__init__(world, parent)
|
||||
self.world = world
|
||||
|
||||
@ -12,14 +12,14 @@ warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QLabel
|
||||
from PyQt5.QtCore import Qt
|
||||
from QPanda3D.QPanda3DWidget import QPanda3DWidget
|
||||
from QPanda3D.Panda3DWorld import Panda3DWorld
|
||||
from QMeta3D.QMeta3DWidget import QMeta3DWidget
|
||||
from QMeta3D.Meta3DWorld import Meta3DWorld
|
||||
from direct.gui.DirectGui import *
|
||||
from direct.gui.OnscreenText import OnscreenText
|
||||
from panda3d.core import *
|
||||
import os
|
||||
|
||||
class DebugGUIWorld(Panda3DWorld):
|
||||
class DebugGUIWorld(Meta3DWorld):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@ -186,7 +186,7 @@ class DebugGUIWorld(Panda3DWorld):
|
||||
"""按钮点击事件"""
|
||||
print("✓ 按钮被点击了!")
|
||||
|
||||
class DebugWidget(QPanda3DWidget):
|
||||
class DebugWidget(QMeta3DWidget):
|
||||
def __init__(self, world, parent=None):
|
||||
super().__init__(world, parent)
|
||||
self.world = world
|
||||
|
||||
@ -12,14 +12,14 @@ warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow
|
||||
from PyQt5.QtCore import Qt
|
||||
from QPanda3D.QPanda3DWidget import QPanda3DWidget
|
||||
from QPanda3D.Panda3DWorld import Panda3DWorld
|
||||
from QMeta3D.QMeta3DWidget import QMeta3DWidget
|
||||
from QMeta3D.Meta3DWorld import Meta3DWorld
|
||||
from direct.gui.DirectGui import *
|
||||
from direct.gui.OnscreenText import OnscreenText
|
||||
from panda3d.core import *
|
||||
import os
|
||||
|
||||
class QtGUITestWorld(Panda3DWorld):
|
||||
class QtGUITestWorld(Meta3DWorld):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@ -109,7 +109,7 @@ class QtGUITestWorld(Panda3DWorld):
|
||||
"""按钮点击事件"""
|
||||
print("✓ 按钮被点击了!")
|
||||
|
||||
class QtGUITestWidget(QPanda3DWidget):
|
||||
class QtGUITestWidget(QMeta3DWidget):
|
||||
def __init__(self, world, parent=None):
|
||||
super().__init__(world, parent)
|
||||
self.world = world
|
||||
|
||||
@ -13,13 +13,13 @@ import sys
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QLabel
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QMouseEvent
|
||||
from QPanda3D.QPanda3DWidget import QPanda3DWidget
|
||||
from QPanda3D.Panda3DWorld import Panda3DWorld
|
||||
from QMeta3D.QMeta3DWidget import QMeta3DWidget
|
||||
from QMeta3D.Meta3DWorld import Meta3DWorld
|
||||
from direct.gui.DirectGui import *
|
||||
from direct.gui.OnscreenText import OnscreenText
|
||||
from panda3d.core import *
|
||||
|
||||
class QtGUIFixWorld(Panda3DWorld):
|
||||
class QtGUIFixWorld(Meta3DWorld):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@ -194,7 +194,7 @@ class QtGUIFixWorld(Panda3DWorld):
|
||||
print(f"Qt事件处理失败: {str(e)}")
|
||||
return False
|
||||
|
||||
class CustomQPanda3DWidget(QPanda3DWidget):
|
||||
class CustomQMeta3DWidget(QMeta3DWidget):
|
||||
"""自定义QPanda3DWidget,支持事件转发"""
|
||||
def __init__(self, world, parent=None):
|
||||
super().__init__(world, parent)
|
||||
@ -241,7 +241,7 @@ def main():
|
||||
world = QtGUIFixWorld()
|
||||
|
||||
# 创建自定义Panda3D部件
|
||||
pandaWidget = CustomQPanda3DWidget(world)
|
||||
pandaWidget = CustomQMeta3DWidget(world)
|
||||
layout.addWidget(pandaWidget)
|
||||
|
||||
mainWindow.setCentralWidget(centralWidget)
|
||||
|
||||
@ -11,13 +11,13 @@ warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QLabel
|
||||
from PyQt5.QtCore import Qt
|
||||
from QPanda3D.QPanda3DWidget import QPanda3DWidget
|
||||
from QPanda3D.Panda3DWorld import Panda3DWorld
|
||||
from QMeta3D.QMeta3DWidget import QMeta3DWidget
|
||||
from QMeta3D.Meta3DWorld import Meta3DWorld
|
||||
from direct.gui.DirectGui import *
|
||||
from direct.gui.OnscreenText import OnscreenText
|
||||
from panda3d.core import *
|
||||
|
||||
class QtOnlyWorld(Panda3DWorld):
|
||||
class QtOnlyWorld(Meta3DWorld):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@ -139,7 +139,7 @@ def main():
|
||||
world = QtOnlyWorld()
|
||||
|
||||
# 创建Panda3D部件
|
||||
pandaWidget = QPanda3DWidget(world)
|
||||
pandaWidget = QMeta3DWidget(world)
|
||||
layout.addWidget(pandaWidget)
|
||||
|
||||
mainWindow.setCentralWidget(centralWidget)
|
||||
|
||||
@ -12,14 +12,14 @@ warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QLabel, QPushButton
|
||||
from PyQt5.QtCore import Qt
|
||||
from QPanda3D.QPanda3DWidget import QPanda3DWidget
|
||||
from QPanda3D.Panda3DWorld import Panda3DWorld
|
||||
from QMeta3D.QMeta3DWidget import QMeta3DWidget
|
||||
from QMeta3D.Meta3DWorld import Meta3DWorld
|
||||
from direct.showbase.ShowBase import ShowBase
|
||||
from direct.gui.DirectGui import *
|
||||
from direct.gui.OnscreenText import OnscreenText
|
||||
from panda3d.core import *
|
||||
|
||||
class QtTestWorld(Panda3DWorld):
|
||||
class QtTestWorld(Meta3DWorld):
|
||||
"""Qt集成环境测试"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
@ -168,7 +168,7 @@ def testQtEnvironment():
|
||||
world = QtTestWorld()
|
||||
|
||||
# 创建Panda3D部件
|
||||
pandaWidget = QPanda3DWidget(world)
|
||||
pandaWidget = QMeta3DWidget(world)
|
||||
layout.addWidget(pandaWidget)
|
||||
|
||||
mainWindow.setCentralWidget(centralWidget)
|
||||
|
||||
@ -11,9 +11,9 @@ warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QLabel, QPushButton, QHBoxLayout
|
||||
from PyQt5.QtCore import Qt
|
||||
from QPanda3D.QPanda3DWidget import QPanda3DWidget
|
||||
from QMeta3D.QMeta3DWidget import QMeta3DWidget
|
||||
sys.path.append('..')
|
||||
from main import MyWorld, CustomPanda3DWidget
|
||||
from main import MyWorld, CustomMeta3DWidget
|
||||
|
||||
def main():
|
||||
print("启动简化坐标轴测试...")
|
||||
@ -42,7 +42,7 @@ def main():
|
||||
world = MyWorld()
|
||||
|
||||
# 创建部件
|
||||
pandaWidget = CustomPanda3DWidget(world)
|
||||
pandaWidget = CustomMeta3DWidget(world)
|
||||
layout.addWidget(pandaWidget)
|
||||
|
||||
mainWindow.setCentralWidget(centralWidget)
|
||||
|
||||
@ -11,12 +11,12 @@ warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QLabel
|
||||
from PyQt5.QtCore import Qt
|
||||
from QPanda3D.QPanda3DWidget import QPanda3DWidget
|
||||
from QPanda3D.Panda3DWorld import Panda3DWorld
|
||||
from QMeta3D.QMeta3DWidget import QMeta3DWidget
|
||||
from QMeta3D.Meta3DWorld import Meta3DWorld
|
||||
from panda3d.core import *
|
||||
from direct.task import Task
|
||||
|
||||
class SizeTestWorld(Panda3DWorld):
|
||||
class SizeTestWorld(Meta3DWorld):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@ -93,7 +93,7 @@ class SizeTestWorld(Panda3DWorld):
|
||||
# 每5秒检查一次
|
||||
return task.again
|
||||
|
||||
class CustomSizeTestWidget(QPanda3DWidget):
|
||||
class CustomSizeTestWidget(QMeta3DWidget):
|
||||
"""支持尺寸获取的测试部件"""
|
||||
def __init__(self, world, parent=None):
|
||||
super().__init__(world, parent)
|
||||
|
||||
@ -33,8 +33,13 @@ class VideoManager:
|
||||
|
||||
# 创建视频纹理
|
||||
if video_path and os.path.exists(video_path):
|
||||
# Convert Windows path to Panda3D compatible path format
|
||||
from panda3d.core import Filename
|
||||
panda_path = Filename.fromOsSpecific(video_path)
|
||||
converted_path = str(panda_path)
|
||||
|
||||
movie_texture = MovieTexture(name)
|
||||
success = movie_texture.read(video_path)
|
||||
success = movie_texture.read(converted_path)
|
||||
|
||||
if success:
|
||||
video_screen.setTexture(movie_texture)
|
||||
@ -43,7 +48,7 @@ class VideoManager:
|
||||
video_obj = {
|
||||
'node': video_screen,
|
||||
'texture': movie_texture,
|
||||
'path': video_path,
|
||||
'path': converted_path,
|
||||
'name': name,
|
||||
'type': 'movie',
|
||||
'is_playing': False
|
||||
@ -62,7 +67,7 @@ class VideoManager:
|
||||
print(f"✓ 视频屏幕创建成功: {name}")
|
||||
return video_screen
|
||||
else:
|
||||
print(f"✗ 无法加载视频: {video_path}")
|
||||
print(f"✗ 无法加载视频: {converted_path}")
|
||||
# 创建占位符纹理
|
||||
self._create_placeholder_texture(video_screen, name)
|
||||
else:
|
||||
@ -103,8 +108,13 @@ class VideoManager:
|
||||
|
||||
# 创建视频纹理
|
||||
if video_path and os.path.exists(video_path):
|
||||
# Convert Windows path to Panda3D compatible path format
|
||||
from panda3d.core import Filename
|
||||
panda_path = Filename.fromOsSpecific(video_path)
|
||||
converted_path = str(panda_path)
|
||||
|
||||
movie_texture = MovieTexture(name)
|
||||
success = movie_texture.read(video_path)
|
||||
success = movie_texture.read(converted_path)
|
||||
|
||||
if success:
|
||||
sphere.setTexture(movie_texture)
|
||||
@ -113,7 +123,7 @@ class VideoManager:
|
||||
video_obj = {
|
||||
'node': sphere,
|
||||
'texture': movie_texture,
|
||||
'path': video_path,
|
||||
'path': converted_path,
|
||||
'name': name,
|
||||
'type': 'spherical',
|
||||
'is_playing': True
|
||||
|
||||
@ -791,7 +791,7 @@ class GUIManager:
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
def createGUI3DImage(self, pos=(0, 0, 0), image_path=None, size=1.0):
|
||||
def createGUI3DImage(self, pos=(0, 0, 0), image_path=None, size=(1.0,1.0,1.0)):
|
||||
"""创建3D空间图片"""
|
||||
try:
|
||||
|
||||
@ -823,7 +823,7 @@ class GUIManager:
|
||||
# 参数类型检查和转换
|
||||
if isinstance(size, (list, tuple)):
|
||||
if len(size) >= 2:
|
||||
x_size, y_size = float(size[0]), float(size[1])
|
||||
x_size, y_size = float(size[0]), float(size[2])
|
||||
else:
|
||||
x_size = y_size = float(size[0]) if size else 1.0
|
||||
else:
|
||||
@ -831,7 +831,7 @@ class GUIManager:
|
||||
|
||||
# 创建卡片
|
||||
cm = CardMaker('gui_3d_image')
|
||||
cm.setFrame(-x_size / 2, x_size / 2, -y_size / 2, y_size / 2)
|
||||
cm.setFrame(-x_size, x_size, -y_size, y_size)
|
||||
|
||||
# 创建3D图像节点
|
||||
# image_node = self.world.render.attachNewNode(cm.generate())
|
||||
@ -1375,8 +1375,13 @@ class GUIManager:
|
||||
print(f"❌ 视频文件不存在: {video_path}")
|
||||
return False
|
||||
|
||||
# Convert Windows path to Panda3D compatible path format
|
||||
from panda3d.core import Filename
|
||||
panda_path = Filename.fromOsSpecific(video_path)
|
||||
converted_path = str(panda_path)
|
||||
|
||||
# 加载新的视频纹理
|
||||
movie_texture = self._loadMovieTexture(video_path)
|
||||
movie_texture = self._loadMovieTexture(video_path) # Pass original path for existence check
|
||||
if movie_texture:
|
||||
# 清除现有的纹理
|
||||
video_screen.clearTexture()
|
||||
@ -1405,15 +1410,15 @@ class GUIManager:
|
||||
|
||||
# 保存新的视频纹理引用到PythonTag
|
||||
video_screen.setPythonTag("movie_texture", movie_texture)
|
||||
video_screen.setTag("video_path", video_path)
|
||||
video_screen.setTag("video_path", converted_path) # Store converted path
|
||||
|
||||
# 确保视频屏幕有正确的材质
|
||||
self._ensureVideoScreenMaterial(video_screen)
|
||||
|
||||
print(f"✅ 成功加载新视频: {video_path}")
|
||||
print(f"✅ 成功加载新视频: {converted_path}")
|
||||
return True
|
||||
else:
|
||||
print(f"❌ 无法加载视频文件: {video_path}")
|
||||
print(f"❌ 无法加载视频文件: {converted_path}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
@ -1425,7 +1430,7 @@ class GUIManager:
|
||||
def _loadMovieTexture(self, video_path):
|
||||
"""加载视频纹理的兼容方法"""
|
||||
try:
|
||||
from panda3d.core import Texture, MovieTexture
|
||||
from panda3d.core import Texture, MovieTexture, Filename
|
||||
import os
|
||||
|
||||
# 检查文件是否存在
|
||||
@ -1433,12 +1438,16 @@ class GUIManager:
|
||||
print(f"❌ 视频文件不存在: {video_path}")
|
||||
return None
|
||||
|
||||
print(f"🔍 尝试加载视频文件: {video_path}")
|
||||
# Convert Windows path to Panda3D compatible path format
|
||||
panda_path = Filename.fromOsSpecific(video_path)
|
||||
converted_path = str(panda_path)
|
||||
|
||||
print(f"🔍 尝试加载视频文件: {converted_path}")
|
||||
|
||||
# 方法1: 尝试使用 MovieTexture(专门用于视频)
|
||||
try:
|
||||
movie_texture = MovieTexture(video_path)
|
||||
if movie_texture.read(video_path):
|
||||
movie_texture = MovieTexture(converted_path)
|
||||
if movie_texture.read(converted_path):
|
||||
print("✅ 使用 MovieTexture 成功加载视频")
|
||||
self._configureVideoTexture(movie_texture)
|
||||
return movie_texture
|
||||
@ -1449,7 +1458,7 @@ class GUIManager:
|
||||
|
||||
# 方法2: 尝试使用 loader.loadTexture
|
||||
try:
|
||||
movie_texture = self.world.loader.loadTexture(video_path)
|
||||
movie_texture = self.world.loader.loadTexture(converted_path)
|
||||
if movie_texture and hasattr(movie_texture, 'is_playable') and movie_texture.is_playable():
|
||||
print("✅ 使用 loader.loadTexture 成功加载视频纹理")
|
||||
self._configureVideoTexture(movie_texture)
|
||||
@ -1462,7 +1471,7 @@ class GUIManager:
|
||||
# 方法3: 尝试使用 Texture.read(作为最后备选)
|
||||
try:
|
||||
texture = Texture()
|
||||
if texture.read(video_path):
|
||||
if texture.read(converted_path):
|
||||
print("✅ 使用 Texture.read 成功加载(可能作为静态纹理)")
|
||||
self._configureVideoTexture(texture)
|
||||
return texture
|
||||
|
||||
4
main.py
4
main.py
@ -15,7 +15,7 @@ from PyQt5.QtWidgets import (QApplication, QMainWindow, QMenuBar, QMenu, QAction
|
||||
from PyQt5.QtCore import Qt, QDir, QUrl
|
||||
from PyQt5.QtGui import QDrag, QPainter, QPixmap
|
||||
from PyQt5.QtWidgets import QFileSystemModel
|
||||
from QPanda3D.QPanda3DWidget import QPanda3DWidget
|
||||
from QMeta3D.QMeta3DWidget import QMeta3DWidget
|
||||
from panda3d.core import loadPrcFileData
|
||||
loadPrcFileData("", "assertions 0")
|
||||
from core.world import CoreWorld
|
||||
@ -29,7 +29,7 @@ from gui.gui_manager import GUIManager
|
||||
from core.terrain_manager import TerrainManager
|
||||
from scene.scene_manager import SceneManager
|
||||
from project.project_manager import ProjectManager
|
||||
from ui.widgets import CustomPanda3DWidget, CustomFileView, CustomTreeWidget
|
||||
from ui.widgets import CustomMeta3DWidget, CustomFileView, CustomTreeWidget
|
||||
from ui.property_panel import PropertyPanelManager
|
||||
from ui.interface_manager import InterfaceManager
|
||||
from panda3d.core import (CardMaker, Vec4, Vec3, ColorAttrib, MaterialAttrib,
|
||||
|
||||
@ -1,11 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
项目管理器 - 负责项目的生命周期管理
|
||||
处理项目创建、打开、保存、打包等功能
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
@ -22,13 +14,9 @@ from PyQt5.QtCore import Qt
|
||||
from ui.widgets import NewProjectDialog, UniversalMessageDialog
|
||||
|
||||
class ProjectManager:
|
||||
"""项目管理器 - 统一管理项目的生命周期"""
|
||||
|
||||
|
||||
def __init__(self, world):
|
||||
"""初始化项目管理器
|
||||
Args:
|
||||
world: 主程序world对象引用
|
||||
"""
|
||||
|
||||
self.world = world
|
||||
self.current_project_path = None
|
||||
self.project_config = None
|
||||
@ -821,353 +809,6 @@ class ProjectManager:
|
||||
shutil.copy2(template_path, app_path)
|
||||
print(f"✓ 应用程序主文件已从模板创建: {app_path}")
|
||||
|
||||
# def _createAppFile(self, build_dir, project_name):
|
||||
# """创建应用程序主文件"""
|
||||
# app_code = f'''#!/usr/bin/env python3
|
||||
# # -*- coding: utf-8 -*-
|
||||
#
|
||||
# """
|
||||
# {project_name} - Panda3D应用程序
|
||||
# 使用Panda3D引擎编辑器创建
|
||||
# """
|
||||
#
|
||||
# from __future__ import print_function
|
||||
#
|
||||
# import json
|
||||
#
|
||||
# from direct.actor.Actor import Actor
|
||||
# from panda3d.core import TextNode, CardMaker, TextureStage, NodePath
|
||||
# #获取渲染管线路径
|
||||
# import sys
|
||||
# import os
|
||||
#
|
||||
# render_pipeline_path = 'RenderPipelineFile'
|
||||
# project_root = os.path.dirname(os.path.abspath(__file__))
|
||||
# sys.path.insert(0,project_root)
|
||||
# sys.path.insert(0,render_pipeline_path)
|
||||
#
|
||||
# import math
|
||||
# from random import random,randint,seed
|
||||
# from panda3d.core import Vec3,load_prc_file_data,Filename
|
||||
# from direct.showbase.ShowBase import ShowBase
|
||||
#
|
||||
# os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
||||
#
|
||||
# class MainApp(ShowBase):
|
||||
# def __init__(self):
|
||||
# load_prc_file_data("","""
|
||||
# win-size 1200 720
|
||||
# window-title Render
|
||||
# """)
|
||||
#
|
||||
# pipeline_path = "../../"
|
||||
#
|
||||
# if not os.path.isfile(os.path.join(pipeline_path,"setup.py")):
|
||||
# pipeline_path = "../../RenderPipeline"
|
||||
#
|
||||
# sys.path.insert(0,pipeline_path)
|
||||
#
|
||||
# from rpcore import RenderPipeline,SpotLight
|
||||
# self.render_pipeline = RenderPipeline()
|
||||
# self.render_pipeline.create(self)
|
||||
#
|
||||
# from rpcore.util.movement_controller import MovementController
|
||||
#
|
||||
# self.render_pipeline.daytime_mgr.time = "12:00"
|
||||
# self._loadFont()
|
||||
#
|
||||
# self.loadFullScene()
|
||||
# self.loadGUIFromJSON()
|
||||
#
|
||||
# self.controller = MovementController(self)
|
||||
# self.controller.set_initial_position(
|
||||
# Vec3(-7.5,-5.3,1.8),Vec3(-5.9,-4.0,1.6))
|
||||
# self.controller.setup()
|
||||
#
|
||||
# base.accept("l",self.tour)
|
||||
#
|
||||
# def _loadFont(self):
|
||||
# """加载中文字体"""
|
||||
# self.chinese_font = None
|
||||
# try:
|
||||
# self.chinese_font = self.loader.loadFont('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc')
|
||||
# if not self.chinese_font:
|
||||
# print("警告: 无法加载中文字体,将使用默认字体")
|
||||
# else:
|
||||
# print("✓ 中文字体加载成功")
|
||||
# except:
|
||||
# print("警告: 无法加载中文字体,将使用默认字体")
|
||||
# self.chinese_font = None
|
||||
#
|
||||
# def getChineseFont(self):
|
||||
# """获取中文字体"""
|
||||
# return self.chinese_font
|
||||
#
|
||||
# def loadFullScene(self):
|
||||
# """加载完整场景,包括所有元素"""
|
||||
# try:
|
||||
# scene_file = "scene.bam"
|
||||
# if os.path.exists(scene_file):
|
||||
# # 使用readBamFile加载完整场景
|
||||
# from panda3d.core import BamCache
|
||||
# BamCache.getGlobalPtr().setActive(False) # 禁用缓存以避免问题
|
||||
#
|
||||
# scene = self.loader.loadModel(Filename.fromOsSpecific(scene_file))
|
||||
# if scene:
|
||||
# scene.reparentTo(self.render)
|
||||
# self.render_pipeline.prepare_scene(scene)
|
||||
# print("✓ 完整场景加载成功")
|
||||
#
|
||||
# # 处理场景中的各种元素
|
||||
# self.processSceneElements(scene)
|
||||
# else:
|
||||
# print("⚠️ 场景文件加载失败")
|
||||
# else:
|
||||
# print("⚠️ 未找到场景文件")
|
||||
# except Exception as e:
|
||||
# print(f"加载完整场景时出错: {{str(e)}}")
|
||||
# import traceback
|
||||
# traceback.print_exc()
|
||||
#
|
||||
# def processSceneElements(self, scene):
|
||||
# """处理场景中的各种元素"""
|
||||
# try:
|
||||
# # 处理光源
|
||||
# self.processLights(scene)
|
||||
#
|
||||
# # 处理GUI元素
|
||||
# self.processGUIElements(scene)
|
||||
#
|
||||
# except Exception as e:
|
||||
# print(f"处理场景元素时出错: {{str(e)}}")
|
||||
#
|
||||
# def processLights(self, scene):
|
||||
# """处理场景中的光源"""
|
||||
# try:
|
||||
# # 查找并处理点光源
|
||||
# point_lights = scene.findAllMatches("**/=element_type=point_light")
|
||||
# for light_node in point_lights:
|
||||
# try:
|
||||
# from RenderPipelineFile.rpcore import PointLight
|
||||
# light = PointLight()
|
||||
#
|
||||
# # 恢复光源属性
|
||||
# if light_node.hasTag("light_energy"):
|
||||
# light.energy = float(light_node.getTag("light_energy"))
|
||||
# else:
|
||||
# light.energy = 5000
|
||||
#
|
||||
# light.radius = 1000
|
||||
# light.inner_radius = 0.4
|
||||
# light.set_color_from_temperature(5 * 1000.0)
|
||||
# light.casts_shadows = True
|
||||
# light.shadow_map_resolution = 256
|
||||
#
|
||||
# light.setPos(light_node.getPos())
|
||||
# self.render_pipeline.add_light(light)
|
||||
# print(f"✓ 点光源 {{light_node.getName()}} 恢复成功")
|
||||
# except Exception as e:
|
||||
# print(f"恢复点光源 {{light_node.getName()}} 失败: {{str(e)}}")
|
||||
#
|
||||
# # 查找并处理聚光灯
|
||||
# spot_lights = scene.findAllMatches("**/=element_type=spot_light")
|
||||
# for light_node in spot_lights:
|
||||
# try:
|
||||
# from RenderPipelineFile.rpcore import SpotLight
|
||||
# light = SpotLight()
|
||||
#
|
||||
# # 恢复光源属性
|
||||
# if light_node.hasTag("light_energy"):
|
||||
# light.energy = float(light_node.getTag("light_energy"))
|
||||
# else:
|
||||
# light.energy = 5000
|
||||
#
|
||||
# light.radius = 1000
|
||||
# light.inner_radius = 0.4
|
||||
# light.set_color_from_temperature(5 * 1000.0)
|
||||
# light.casts_shadows = True
|
||||
# light.shadow_map_resolution = 256
|
||||
#
|
||||
# light.setPos(light_node.getPos())
|
||||
# self.render_pipeline.add_light(light)
|
||||
# print(f"✓ 聚光灯 {{light_node.getName()}} 恢复成功")
|
||||
# except Exception as e:
|
||||
# print(f"恢复聚光灯 {{light_node.getName()}} 失败: {{str(e)}}")
|
||||
#
|
||||
# except Exception as e:
|
||||
# print(f"处理光源时出错: {{str(e)}}")
|
||||
#
|
||||
# def processGUIElements(self, scene):
|
||||
# """处理场景中的GUI元素"""
|
||||
# try:
|
||||
# # 查找并处理2D图像
|
||||
# images_2d = scene.findAllMatches("**/=gui_type=image_2d")
|
||||
# for img_node in images_2d:
|
||||
# try:
|
||||
# # GUI元素通常在场景加载时自动处理
|
||||
# print(f"✓ 2D图像 {{img_node.getName()}} 已加载")
|
||||
# except Exception as e:
|
||||
# print(f"处理2D图像 {{img_node.getName()}} 失败: {{str(e)}}")
|
||||
#
|
||||
# except Exception as e:
|
||||
# print(f"处理GUI元素时出错: {{str(e)}}")
|
||||
#
|
||||
# def tour(self):
|
||||
# mopath = (
|
||||
# (Vec3(-10.8645000458, 9.76458263397, 2.13306283951), Vec3(-133.556228638, -4.23447799683, 0.0)),
|
||||
# (Vec3(-10.6538448334, -5.98406457901, 1.68028640747), Vec3(-59.3999938965, -3.32706642151, 0.0)),
|
||||
# (Vec3(9.58458328247, -5.63625621796, 2.63269257545), Vec3(58.7906494141, -9.40668964386, 0.0)),
|
||||
# (Vec3(6.8135137558, 11.0153560638, 2.25509500504), Vec3(148.762527466, -6.41223621368, 0.0)),
|
||||
# (Vec3(-9.07093334198, 3.65908527374, 1.42396306992), Vec3(245.362503052, -3.59927511215, 0.0)),
|
||||
# (Vec3(-8.75390911102, -3.82727789879, 0.990055501461), Vec3(296.090484619, -0.604830980301, 0.0)),
|
||||
# )
|
||||
# self.controller.play_motion_path(mopath,3.0)
|
||||
#
|
||||
# def loadGUIFromJSON(self):
|
||||
# gui_json_path = "gui/gui_elements.json"
|
||||
#
|
||||
# try:
|
||||
# if os.path.exists(gui_json_path):
|
||||
# with open(gui_json_path, "r", encoding="utf-8") as f:
|
||||
# content = f.read().strip()
|
||||
# if content:
|
||||
# gui_data = json.loads(content)
|
||||
# self.createGUIElement(gui_data)
|
||||
# except Exception as e:
|
||||
# print(f"加载GUI元素失败: {{str(e)}}")
|
||||
# import traceback
|
||||
# traceback.print_exc()
|
||||
#
|
||||
# def createGUIElement(self,element_data):
|
||||
# try:
|
||||
# processed_names = set()
|
||||
# element_original_data={{}}
|
||||
# for i, gui_info in enumerate(element_data):
|
||||
# name = gui_info.get("name", f"gui_element_{{i}}")
|
||||
# element_original_data[name] = {
|
||||
# "scale": gui_info.get("scale", [1, 1, 1]),
|
||||
# "position": gui_info.get("position", [0, 0, 0]),
|
||||
# "parent_name": gui_info.get("parent_name")
|
||||
# }
|
||||
# valid_parents = set()
|
||||
# for gui_info in element_data:
|
||||
# name = gui_info.get("name", f"gui_element_{{gui_info.get('index', 0)}}")
|
||||
# valid_parents.add(name)
|
||||
#
|
||||
# for i ,gui_info in enumerate(element_data):
|
||||
# try:
|
||||
# gui_type = gui_info.get("type","unknown")
|
||||
# name = gui_info.get("name",f"gui_element_{{i}}")
|
||||
# position = gui_info.get("position",[0,0,0])
|
||||
# scale = gui_info.get("scale",[1,1,1])
|
||||
# tags = gui_info.get("tags",{{}})
|
||||
# text = gui_info.get("text","")
|
||||
# image_path = gui_info.get("image_path","")
|
||||
# video_path = gui_info.get("video_path","")
|
||||
# bg_image_path = gui_info.get("bg_image_path","")
|
||||
# parent_name = gui_info.get("parent_name")
|
||||
#
|
||||
# if name in processed_names:
|
||||
# continue
|
||||
#
|
||||
# processed_names.add(name)
|
||||
#
|
||||
# absolute_position = list(position)
|
||||
# absolute_scale = list(scale)
|
||||
#
|
||||
# if parent_name and parent_name in element_original_data:
|
||||
# parent_data = element_original_data[parent_name]
|
||||
# parent_scale = parent_data["scale"]
|
||||
#
|
||||
# if gui_type in ["3d_text", "3d_image", "button", "label", "entry", "2d_image",
|
||||
# "2d_video_screen"]:
|
||||
# # 位置需要乘以父级缩放来得到绝对位置
|
||||
# for j in range(min(len(absolute_position), len(parent_scale))):
|
||||
# absolute_position[j] *= parent_scale[j] if len(parent_scale) > j else parent_scale[0]
|
||||
#
|
||||
# # 缩放需要乘以父级缩放来得到绝对缩放
|
||||
# for j in range(min(len(absolute_scale), len(parent_scale))):
|
||||
# absolute_scale[j] *= parent_scale[j] if len(parent_scale) > j else parent_scale[0]
|
||||
#
|
||||
# new_element = None
|
||||
#
|
||||
# if gui_type =="3d_text":
|
||||
# size = absolute_scale[0] if absolute_scale and len(absolute_scale) > 0 else 0.5
|
||||
# new_element = self.createGUI3DText(
|
||||
# pos = tuple(absolute_position),
|
||||
# text = text,
|
||||
# size = size
|
||||
# )
|
||||
# elif gui_type == "button":
|
||||
# # 确保传入正确的参数类型
|
||||
# new_element = self.createGUIButton(
|
||||
# pos=tuple(absolute_position),
|
||||
# text=text,
|
||||
# size=absolute_scale[0] if absolute_scale and len(absolute_scale) > 0 else 1.0,
|
||||
# )
|
||||
# except Exception as e:
|
||||
# print(f"重建GUI元素失败 {{name}}: {{e}}")
|
||||
# import traceback
|
||||
# traceback.print_exc()
|
||||
# continue
|
||||
# except Exception as e:
|
||||
# print(f"重建GUI元素失败: {{str(e)}}")
|
||||
#
|
||||
# def createGUIButton(self, pos=(0, 0, 0), text="按钮", size=0.1,command=None):
|
||||
# from direct.gui.DirectGui import DirectButton
|
||||
#
|
||||
# button = DirectButton(
|
||||
# text=text,
|
||||
# pos=(pos[0], pos[1], pos[2]), # 保持正确的坐标格式
|
||||
# scale=size, # size 应该是数值而不是元组
|
||||
# frameColor=(0.2, 0.6, 0.8, 1),
|
||||
# text_font=self.getChineseFont() if self.getChineseFont() else None,
|
||||
# rolloverSound=None,
|
||||
# clickSound=None,
|
||||
# parent=None,
|
||||
# command=command
|
||||
# )
|
||||
#
|
||||
# def createGUI3DText(self, pos=(0, 0, 0), text="3D文本", size=0.5):
|
||||
# """创建3D文本GUI元素"""
|
||||
# try:
|
||||
# # 创建文本节点
|
||||
# text_node = TextNode("gui_3d_text")
|
||||
# text_node.setText(text)
|
||||
# text_node.setAlign(TextNode.ACenter)
|
||||
#
|
||||
# # 设置字体(如果可用)
|
||||
# if self.getChineseFont():
|
||||
# text_node.setFont(self.getChineseFont())
|
||||
#
|
||||
# # 创建节点路径并添加到场景
|
||||
# text_np = self.render.attachNewNode(text_node)
|
||||
#
|
||||
# # 设置位置和大小
|
||||
# text_np.setPos(Vec3(pos[0], pos[1], pos[2]))
|
||||
# text_np.setScale(size)
|
||||
#
|
||||
# # 设置面向摄像机
|
||||
# #text_np.setBillboardPointEye()
|
||||
#
|
||||
# # 设置渲染属性
|
||||
# text_np.setBin("fixed", 40)
|
||||
# text_np.setDepthWrite(False)
|
||||
#
|
||||
# return text_np
|
||||
# except Exception as e:
|
||||
# print(f"❌ 创建3D文本失败: {{str(e)}}")
|
||||
# import traceback
|
||||
# traceback.print_exc()
|
||||
# return None
|
||||
#
|
||||
# MainApp().run()
|
||||
# '''
|
||||
#
|
||||
# app_path = os.path.join(build_dir, "main.py")
|
||||
# with open(app_path, "w", encoding="utf-8") as f:
|
||||
# f.write(app_code)
|
||||
|
||||
def _createStandardSetupFile(self, build_dir, project_name):
|
||||
"""创建优化的标准setup.py文件"""
|
||||
setup_code = f'''#!/usr/bin/env python3
|
||||
|
||||
354
run_complete_analysis.py
Normal file
354
run_complete_analysis.py
Normal file
@ -0,0 +1,354 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
完整的开源率分析脚本
|
||||
该脚本将执行完整的测试流程并生成准确报告
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def run_command(command, ignore_failure=False):
|
||||
"""运行命令并返回结果"""
|
||||
try:
|
||||
print(f"执行命令: {command}")
|
||||
result = subprocess.run(command, shell=True, capture_output=True, text=True)
|
||||
if result.returncode != 0 and not ignore_failure:
|
||||
print(f"命令执行失败: {result.stderr}")
|
||||
return False
|
||||
print("命令执行成功")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"执行命令时出错: {e}")
|
||||
return False
|
||||
|
||||
def load_cloc_data(path="cloc.json"):
|
||||
"""加载并解析cloc统计数据"""
|
||||
if not os.path.exists(path):
|
||||
print(f"❌ 未找到 {path} 文件")
|
||||
return None
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
def load_scancode_data(path="summary.json"):
|
||||
"""加载并解析ScanCode统计数据"""
|
||||
if not os.path.exists(path):
|
||||
print(f"❌ 未找到 {path} 文件")
|
||||
return None
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
def get_licensed_files_details(scancode_data):
|
||||
"""获取含许可证文件的详细信息"""
|
||||
if not scancode_data:
|
||||
return []
|
||||
|
||||
files = scancode_data.get("files", [])
|
||||
licensed_files = []
|
||||
|
||||
# 定义需要排除的目录和文件模式
|
||||
exclude_patterns = [
|
||||
"/venv/",
|
||||
"/.git/",
|
||||
"/__pycache__/",
|
||||
"/.idea/",
|
||||
"/.vscode/",
|
||||
"/build/",
|
||||
"/dist/",
|
||||
".egg-info",
|
||||
"/Resources/",
|
||||
"/icons/",
|
||||
"/tex/",
|
||||
"cloc.json",
|
||||
"detailed_cloc.txt",
|
||||
"summary.json",
|
||||
"完整开源率分析报告.txt",
|
||||
"run_complete_analysis.py",
|
||||
]
|
||||
|
||||
for file in files:
|
||||
# 获取文件路径
|
||||
file_path = file.get("path", "")
|
||||
|
||||
# 只处理类型为"file"的条目
|
||||
if file.get("type") != "file":
|
||||
continue
|
||||
|
||||
# 检查是否应该排除该文件
|
||||
should_exclude = False
|
||||
for pattern in exclude_patterns:
|
||||
if pattern in file_path:
|
||||
should_exclude = True
|
||||
break
|
||||
|
||||
# 如果应该排除,则跳过该文件
|
||||
if should_exclude:
|
||||
continue
|
||||
|
||||
# 检查是否有许可证信息
|
||||
if file.get("detected_license_expression") or file.get("license_detections"):
|
||||
licensed_files.append({
|
||||
"path": file_path,
|
||||
"license": file.get("detected_license_expression", "Unknown"),
|
||||
"detections": file.get("license_detections", [])
|
||||
})
|
||||
|
||||
return licensed_files
|
||||
|
||||
def get_file_code_lines():
|
||||
"""从detailed_cloc.txt获取文件代码行数"""
|
||||
file_code_lines = {}
|
||||
|
||||
if not os.path.exists("detailed_cloc.txt"):
|
||||
print("❌ 未找到 detailed_cloc.txt 文件")
|
||||
return file_code_lines
|
||||
|
||||
with open("detailed_cloc.txt", "r") as f:
|
||||
cloc_lines = f.readlines()
|
||||
|
||||
# 解析cloc输出,创建文件路径到代码行数的映射
|
||||
for line in cloc_lines[3:]: # 跳过标题行
|
||||
parts = line.strip().split()
|
||||
if len(parts) >= 4:
|
||||
try:
|
||||
file_path = parts[0]
|
||||
code_lines = int(parts[-1])
|
||||
# 标准化路径格式
|
||||
if file_path.startswith('./'):
|
||||
file_path = file_path[2:]
|
||||
file_code_lines[file_path] = code_lines
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
return file_code_lines
|
||||
|
||||
def calculate_accurate_open_source_lines(licensed_files_details, file_code_lines):
|
||||
"""计算准确的开源代码行数"""
|
||||
total_licensed_code_lines = 0
|
||||
found_files = 0
|
||||
detailed_files = []
|
||||
|
||||
for file_info in licensed_files_details:
|
||||
file_path = file_info["path"]
|
||||
|
||||
# 将文件路径标准化
|
||||
normalized_path = file_path
|
||||
if normalized_path.startswith('EG/'):
|
||||
normalized_path = normalized_path[3:] # 去掉开头的EG/
|
||||
|
||||
if normalized_path in file_code_lines:
|
||||
code_lines = file_code_lines[normalized_path]
|
||||
total_licensed_code_lines += code_lines
|
||||
found_files += 1
|
||||
detailed_files.append({
|
||||
"path": file_path,
|
||||
"code_lines": code_lines,
|
||||
"license": file_info["license"]
|
||||
})
|
||||
else:
|
||||
# 尝试其他可能的路径格式
|
||||
alt_path1 = './' + normalized_path
|
||||
alt_path2 = 'EG/' + normalized_path
|
||||
if alt_path1 in file_code_lines:
|
||||
code_lines = file_code_lines[alt_path1]
|
||||
total_licensed_code_lines += code_lines
|
||||
found_files += 1
|
||||
detailed_files.append({
|
||||
"path": file_path,
|
||||
"code_lines": code_lines,
|
||||
"license": file_info["license"]
|
||||
})
|
||||
elif alt_path2 in file_code_lines:
|
||||
code_lines = file_code_lines[alt_path2]
|
||||
total_licensed_code_lines += code_lines
|
||||
found_files += 1
|
||||
detailed_files.append({
|
||||
"path": file_path,
|
||||
"code_lines": code_lines,
|
||||
"license": file_info["license"]
|
||||
})
|
||||
|
||||
return total_licensed_code_lines, detailed_files
|
||||
|
||||
def generate_detailed_report():
|
||||
"""生成详细报告"""
|
||||
# 加载数据
|
||||
cloc_data = load_cloc_data("cloc.json")
|
||||
scancode_data = load_scancode_data("summary.json")
|
||||
file_code_lines = get_file_code_lines()
|
||||
|
||||
if not cloc_data or not scancode_data:
|
||||
print("无法加载必要数据文件")
|
||||
return False
|
||||
|
||||
# 获取含许可证文件详情
|
||||
licensed_files_details = get_licensed_files_details(scancode_data)
|
||||
|
||||
# 计算准确的开源代码行数
|
||||
accurate_open_source_lines, detailed_files = calculate_accurate_open_source_lines(
|
||||
licensed_files_details, file_code_lines)
|
||||
|
||||
# 获取统计数据
|
||||
total_code_lines = cloc_data.get("SUM", {}).get("code", 0)
|
||||
total_files = 1075 # 根据脚本分析得出的实际文件数
|
||||
licensed_files = len(licensed_files_details)
|
||||
|
||||
# 计算开源率
|
||||
open_source_rate = (accurate_open_source_lines / total_code_lines) * 100 if total_code_lines > 0 else 0
|
||||
|
||||
# 创建报告内容
|
||||
report_content = []
|
||||
report_content.append("项目开源率分析完整报告")
|
||||
report_content.append("=" * 50)
|
||||
report_content.append("")
|
||||
|
||||
report_content.append("1. 报告概览")
|
||||
report_content.append("-" * 20)
|
||||
report_content.append(f"项目总文件数: {total_files}")
|
||||
report_content.append(f"含许可证文件数: {licensed_files}")
|
||||
report_content.append(f"项目总代码行数: {total_code_lines}")
|
||||
report_content.append(f"准确开源代码行数: {accurate_open_source_lines}")
|
||||
report_content.append(f"代码开源率: {open_source_rate:.2f}%")
|
||||
report_content.append("")
|
||||
|
||||
report_content.append("2. 各语言代码行数分布(包含文件路径)")
|
||||
report_content.append("-" * 40)
|
||||
|
||||
# 按语言分组显示文件
|
||||
lang_files = {}
|
||||
with open("detailed_cloc.txt", "r") as f:
|
||||
cloc_lines = f.readlines()
|
||||
|
||||
for line in cloc_lines[3:]: # 跳过标题行
|
||||
parts = line.strip().split()
|
||||
if len(parts) >= 4:
|
||||
try:
|
||||
file_path = parts[0]
|
||||
# 从文件路径推断语言(简化处理)
|
||||
if file_path.endswith('.py'):
|
||||
lang = 'Python'
|
||||
elif file_path.endswith('.js'):
|
||||
lang = 'JavaScript'
|
||||
elif file_path.endswith('.cpp') or file_path.endswith('.cc'):
|
||||
lang = 'C++'
|
||||
elif file_path.endswith('.h'):
|
||||
lang = 'C/C++ Header'
|
||||
elif file_path.endswith('.glsl'):
|
||||
lang = 'GLSL'
|
||||
elif file_path.endswith('.qml'):
|
||||
lang = 'QML'
|
||||
elif file_path.endswith('.xml'):
|
||||
lang = 'XML'
|
||||
elif file_path.endswith('.json'):
|
||||
lang = 'JSON'
|
||||
elif file_path.endswith('.md'):
|
||||
lang = 'Markdown'
|
||||
elif file_path.endswith('.html'):
|
||||
lang = 'HTML'
|
||||
elif file_path.endswith('.css'):
|
||||
lang = 'CSS'
|
||||
elif file_path.endswith('.sh'):
|
||||
lang = 'Shell'
|
||||
elif file_path.endswith('.yml') or file_path.endswith('.yaml'):
|
||||
lang = 'YAML'
|
||||
else:
|
||||
lang = 'Other'
|
||||
|
||||
if lang not in lang_files:
|
||||
lang_files[lang] = []
|
||||
lang_files[lang].append((file_path, int(parts[-1])))
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
for lang, files in lang_files.items():
|
||||
report_content.append(f"\n{lang}语言文件:")
|
||||
report_content.append(f" 文件总数: {len(files)}")
|
||||
total_lines = sum([f[1] for f in files])
|
||||
report_content.append(f" 代码行数: {total_lines}")
|
||||
report_content.append(" 文件列表:")
|
||||
for file_path, code_lines in files[:10]: # 只显示前10个文件
|
||||
report_content.append(f" {file_path}: {code_lines} 行")
|
||||
if len(files) > 10:
|
||||
report_content.append(f" ... 还有 {len(files) - 10} 个文件")
|
||||
|
||||
report_content.append("")
|
||||
report_content.append("3. 含许可证的开源文件详情")
|
||||
report_content.append("-" * 30)
|
||||
|
||||
# 按许可证类型分组显示文件
|
||||
files_by_license = {}
|
||||
for file_info in detailed_files:
|
||||
license_type = file_info.get("license", "Unknown")
|
||||
if license_type not in files_by_license:
|
||||
files_by_license[license_type] = []
|
||||
files_by_license[license_type].append(file_info)
|
||||
|
||||
for license_type, files in files_by_license.items():
|
||||
report_content.append(f"\n许可证类型: {license_type}")
|
||||
report_content.append(f" 文件数量: {len(files)}")
|
||||
total_lines = sum([f["code_lines"] for f in files])
|
||||
report_content.append(f" 代码行数: {total_lines}")
|
||||
report_content.append(" 文件列表:")
|
||||
for file_info in files:
|
||||
report_content.append(f" {file_info['path']}: {file_info['code_lines']} 行")
|
||||
|
||||
# 保存报告
|
||||
with open("完整开源率分析报告.txt", "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(report_content))
|
||||
|
||||
print("完整报告已生成:完整开源率分析报告.txt")
|
||||
return True
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("开始执行完整的开源率分析流程...")
|
||||
|
||||
# 步骤1: 执行cloc统计代码行数
|
||||
print("\n步骤1: 执行cloc统计代码行数")
|
||||
cloc_cmd = "cloc --json --fullpath --not-match-d='(venv|\\.git|__pycache__|\\.idea|\\.vscode|build|dist|.*\\.egg-info|Resources/animations|Resources/materials|Resources/models|Resources/textures|icons|tex)' --not-match-f='(cloc.json|detailed_cloc.txt|summary.json|完整开源率分析报告.txt|run_complete_analysis.py)' . > cloc.json"
|
||||
if not run_command(cloc_cmd):
|
||||
print("❌ cloc统计失败")
|
||||
return False
|
||||
|
||||
# 步骤2: 生成详细文件列表
|
||||
print("\n步骤2: 生成详细文件列表")
|
||||
detailed_cloc_cmd = "cloc --by-file --fullpath --not-match-d='(venv|\\.git|__pycache__|\\.idea|\\.vscode|build|dist|.*\\.egg-info|Resources/animations|Resources/materials|Resources/models|Resources/textures|icons|tex)' --not-match-f='(cloc.json|detailed_cloc.txt|summary.json|完整开源率分析报告.txt|run_complete_analysis.py)' . | grep -v \"^\\s*$\" | grep -E \"(\\.py|\\.js|\\.cpp|\\.h|\\.glsl|\\.qml|\\.xml|\\.html|\\.css|\\.java|\\.cs|\\.php)\" > detailed_cloc.txt"
|
||||
if not run_command(detailed_cloc_cmd):
|
||||
print("❌ 生成详细文件列表失败")
|
||||
return False
|
||||
|
||||
# 步骤3: 执行ScanCode扫描许可证
|
||||
print("\n步骤3: 执行ScanCode扫描许可证")
|
||||
scancode_cmd = "scancode --license --classify --summary --json-pp summary.json . --ignore \"venv\" --ignore \".git\" --ignore \"__pycache__\" --ignore \".idea\" --ignore \".vscode\" --ignore \"build\" --ignore \"dist\" --ignore \"*.egg-info\" --ignore \"Resources\" --ignore \"icons\" --ignore \"tex\" --ignore \"cloc.json\" --ignore \"detailed_cloc.txt\" --ignore \"完整开源率分析报告.txt\" --ignore \"run_complete_analysis.py\""
|
||||
# 忽略失败,因为ScanCode会尝试扫描自己生成的summary.json文件导致"失败"
|
||||
run_command(scancode_cmd, ignore_failure=True)
|
||||
|
||||
# 检查summary.json是否生成
|
||||
if not os.path.exists("summary.json"):
|
||||
print("❌ ScanCode未生成summary.json文件")
|
||||
return False
|
||||
|
||||
# 步骤4: 生成详细报告
|
||||
print("\n步骤4: 生成详细报告")
|
||||
if not generate_detailed_report():
|
||||
print("❌ 生成报告失败")
|
||||
return False
|
||||
|
||||
print("\n✅ 完整分析流程执行完成!")
|
||||
print("生成的文件:")
|
||||
print(" - cloc.json: 代码行数统计")
|
||||
print(" - detailed_cloc.txt: 详细文件列表")
|
||||
print(" - summary.json: 许可证扫描结果")
|
||||
print(" - 完整开源率分析报告.txt: 最终报告")
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
success = main()
|
||||
if success:
|
||||
print("\n🎉 所有步骤执行成功!")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("\n❌ 执行过程中出现错误!")
|
||||
sys.exit(1)
|
||||
File diff suppressed because it is too large
Load Diff
@ -836,10 +836,15 @@ class MainApp(ShowBase):
|
||||
return video_screen
|
||||
|
||||
def _loadMovieTexture(self, video_path):
|
||||
from panda3d.core import Texture, MovieTexture
|
||||
from panda3d.core import Texture, MovieTexture, Filename
|
||||
import os
|
||||
movie_texture = MovieTexture(video_path)
|
||||
if movie_texture.read(video_path):
|
||||
|
||||
# Convert Windows path to Panda3D compatible path format
|
||||
panda_path = Filename.fromOsSpecific(video_path)
|
||||
converted_path = str(panda_path)
|
||||
|
||||
movie_texture = MovieTexture(converted_path)
|
||||
if movie_texture.read(converted_path):
|
||||
self._configureVideoTexture(movie_texture)
|
||||
return movie_texture
|
||||
|
||||
|
||||
@ -1,106 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Three.js Panel</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
background: rgba(0,0,0,0.7);
|
||||
color: white;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
#info {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 100;
|
||||
}
|
||||
#canvas-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="info">
|
||||
<h3>场景信息面板</h3>
|
||||
<p>FPS: <span id="fps">0</span></p>
|
||||
<p>对象数: <span id="object-count">0</span></p>
|
||||
</div>
|
||||
<div id="canvas-container"></div>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
||||
<script>
|
||||
// 初始化Three.js场景
|
||||
let scene, camera, renderer;
|
||||
let cube;
|
||||
|
||||
function init() {
|
||||
// 创建场景
|
||||
scene = new THREE.Scene();
|
||||
|
||||
// 创建相机
|
||||
camera = new THREE.PerspectiveCamera(75,
|
||||
document.getElementById('canvas-container').offsetWidth /
|
||||
document.getElementById('canvas-container').offsetHeight,
|
||||
0.1, 1000);
|
||||
|
||||
// 创建渲染器
|
||||
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
||||
renderer.setSize(
|
||||
document.getElementById('canvas-container').offsetWidth,
|
||||
document.getElementById('canvas-container').offsetHeight
|
||||
);
|
||||
document.getElementById('canvas-container').appendChild(renderer.domElement);
|
||||
|
||||
// 添加一个立方体
|
||||
const geometry = new THREE.BoxGeometry();
|
||||
const material = new THREE.MeshBasicMaterial({
|
||||
color: 0x00ff00,
|
||||
wireframe: true
|
||||
});
|
||||
cube = new THREE.Mesh(geometry, material);
|
||||
scene.add(cube);
|
||||
|
||||
camera.position.z = 5;
|
||||
|
||||
// 开始动画循环
|
||||
animate();
|
||||
|
||||
// 监听窗口大小变化
|
||||
window.addEventListener('resize', onWindowResize, false);
|
||||
}
|
||||
|
||||
function onWindowResize() {
|
||||
camera.aspect = document.getElementById('canvas-container').offsetWidth /
|
||||
document.getElementById('canvas-container').offsetHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(
|
||||
document.getElementById('canvas-container').offsetWidth,
|
||||
document.getElementById('canvas-container').offsetHeight
|
||||
);
|
||||
}
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
|
||||
// 旋转立方体
|
||||
cube.rotation.x += 0.01;
|
||||
cube.rotation.y += 0.01;
|
||||
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
// 接收来自Python的消息
|
||||
function updateInfo(data) {
|
||||
document.getElementById('fps').textContent = data.fps || 0;
|
||||
document.getElementById('object-count').textContent = data.objectCount || 0;
|
||||
}
|
||||
|
||||
// 页面加载完成后初始化
|
||||
window.onload = init;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
95
tools/open_source_rate.py
Normal file
95
tools/open_source_rate.py
Normal file
@ -0,0 +1,95 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
THIRD_PARTY_DIR_NAMES = {
|
||||
'node_modules', 'vendor', 'third_party', 'third-party', 'extern', 'external', 'deps',
|
||||
'Cesium', 'Cesium-1.132', 'dist', 'build'
|
||||
}
|
||||
|
||||
CODE_EXTENSIONS = {
|
||||
'.py', '.js', '.ts', '.tsx', '.jsx', '.css', '.scss', '.html', '.c', '.h', '.cpp', '.hpp',
|
||||
'.cc', '.hh', '.m', '.mm', '.java', '.go', '.rs', '.cs', '.vue', '.svelte'
|
||||
}
|
||||
|
||||
SKIP_DIR_NAMES = {
|
||||
'.git', '.hg', '.svn', '__pycache__', '.mypy_cache', '.pytest_cache', '.idea', '.vscode',
|
||||
'.venv', 'venv', 'env', '.tox', '.cache', 'Resources', 'icons', 'tex', 'terminal'
|
||||
}
|
||||
|
||||
MAX_FILE_SIZE_BYTES = 2 * 1024 * 1024 # 2 MiB
|
||||
|
||||
|
||||
def is_third_party(path: Path) -> bool:
|
||||
for part in path.parts:
|
||||
# normalize case on Windows
|
||||
name = part.lower()
|
||||
if name in {n.lower() for n in THIRD_PARTY_DIR_NAMES}:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def should_skip_dir(dirname: str) -> bool:
|
||||
return dirname.lower() in {n.lower() for n in SKIP_DIR_NAMES}
|
||||
|
||||
|
||||
def is_code_file(path: Path) -> bool:
|
||||
return path.suffix.lower() in CODE_EXTENSIONS
|
||||
|
||||
|
||||
def count_lines(path: Path) -> int:
|
||||
try:
|
||||
if path.stat().st_size > MAX_FILE_SIZE_BYTES:
|
||||
return 0
|
||||
# Try text read with universal newlines, fallback to binary
|
||||
try:
|
||||
with path.open('r', encoding='utf-8', errors='ignore') as f:
|
||||
return sum(1 for _ in f)
|
||||
except Exception:
|
||||
with path.open('rb') as f:
|
||||
return f.read().count(b'\n')
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
|
||||
def main(root: Path) -> None:
|
||||
third_party_loc = 0
|
||||
first_party_loc = 0
|
||||
third_party_files = 0
|
||||
first_party_files = 0
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(root):
|
||||
# prune directories
|
||||
dirnames[:] = [d for d in dirnames if not should_skip_dir(d)]
|
||||
|
||||
current = Path(dirpath)
|
||||
current_is_third = is_third_party(current)
|
||||
|
||||
for fn in filenames:
|
||||
p = current / fn
|
||||
if not is_code_file(p):
|
||||
continue
|
||||
loc = count_lines(p)
|
||||
if current_is_third:
|
||||
third_party_loc += loc
|
||||
third_party_files += 1
|
||||
else:
|
||||
first_party_loc += loc
|
||||
first_party_files += 1
|
||||
|
||||
total_loc = first_party_loc + third_party_loc
|
||||
open_source_rate = (third_party_loc / total_loc) * 100 if total_loc else 0.0
|
||||
|
||||
print('Open-Source Rate (by LOC): {:.2f}%'.format(open_source_rate))
|
||||
print('\nBreakdown:')
|
||||
print(' First-party LOC : {} ({} files)'.format(first_party_loc, first_party_files))
|
||||
print(' Third-party LOC : {} ({} files)'.format(third_party_loc, third_party_files))
|
||||
print(' Total LOC : {}'.format(total_loc))
|
||||
print('\nNotes:')
|
||||
print(' - Third-party directories are heuristically detected by common names: {}'.format(', '.join(sorted(THIRD_PARTY_DIR_NAMES))))
|
||||
print(' - Static asset directories are skipped: {}'.format(', '.join(sorted(SKIP_DIR_NAMES))))
|
||||
print(' - Counted code extensions: {}'.format(', '.join(sorted(CODE_EXTENSIONS))))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(Path('.').resolve())
|
||||
|
||||
35
tox.ini
Normal file
35
tox.ini
Normal file
@ -0,0 +1,35 @@
|
||||
[tox]
|
||||
envlist = py310
|
||||
|
||||
[testenv]
|
||||
deps =
|
||||
pytest
|
||||
pytest-qt
|
||||
PyQt5>=5.15.9
|
||||
PySide6>=6.8.1
|
||||
Panda3D>=1.10.15
|
||||
commands =
|
||||
pytest demo/quick_script_test.py
|
||||
|
||||
[testenv:lint]
|
||||
deps =
|
||||
flake8
|
||||
commands =
|
||||
flake8 core/ demo/ scripts/
|
||||
|
||||
[testenv:coverage]
|
||||
deps =
|
||||
pytest
|
||||
pytest-cov
|
||||
PyQt5>=5.15.9
|
||||
PySide6>=6.8.1
|
||||
Panda3D>=1.10.15
|
||||
commands =
|
||||
pytest --cov=core --cov=demo --cov=scripts
|
||||
|
||||
[testenv:memory]
|
||||
deps =
|
||||
memory-profiler
|
||||
Panda3D>=1.10.15
|
||||
commands =
|
||||
python -m memory_profiler memory_test_example.py
|
||||
@ -6,11 +6,11 @@ UI模块
|
||||
- main_window.py: 主窗口设置
|
||||
"""
|
||||
|
||||
from .widgets import CustomPanda3DWidget, CustomFileView, CustomTreeWidget
|
||||
from .widgets import CustomMeta3DWidget, CustomFileView, CustomTreeWidget
|
||||
from .main_window import MainWindow, setup_main_window
|
||||
|
||||
__all__ = [
|
||||
'CustomPanda3DWidget',
|
||||
'CustomMeta3DWidget',
|
||||
'CustomFileView',
|
||||
'CustomTreeWidget',
|
||||
'MainWindow',
|
||||
|
||||
1170
ui/main_window.py
1170
ui/main_window.py
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,7 @@ from PyQt5.QtGui import QColor
|
||||
from PyQt5.QtWidgets import (QLabel, QLineEdit, QDoubleSpinBox, QPushButton,
|
||||
QTreeWidget, QTreeWidgetItem, QMenu, QCheckBox, QComboBox, QHBoxLayout, QWidget,
|
||||
QVBoxLayout, QGroupBox, QGridLayout, QSpinBox, QFileDialog, QMessageBox, QSizePolicy)
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtCore import Qt, QTimer
|
||||
from deploy_libs.unicodedata import normalize
|
||||
from direct.actor.Actor import Actor
|
||||
from direct.gui import DirectGui
|
||||
@ -30,6 +30,8 @@ class PropertyPanelManager:
|
||||
self._propertyLayout = None
|
||||
self._actor_cache = {}
|
||||
self._spherical_video_controls = {}
|
||||
self._transform_monitor_timer = None
|
||||
self._last_transform_values = {}
|
||||
|
||||
self.column_minimum_width = 85
|
||||
|
||||
@ -614,6 +616,9 @@ class PropertyPanelManager:
|
||||
|
||||
def clearPropertyPanel(self):
|
||||
"""清空属性面板"""
|
||||
# 停止变换监控
|
||||
self.stopTransformMonitoring()
|
||||
|
||||
if self._propertyLayout:
|
||||
while self._propertyLayout.count():
|
||||
item = self._propertyLayout.takeAt(0)
|
||||
@ -673,6 +678,7 @@ class PropertyPanelManager:
|
||||
self.active_check = QCheckBox()
|
||||
# 根据模型的实际可见性状态设置复选框
|
||||
self.active_check.setChecked(user_visible)
|
||||
self.active_check.stateChanged.connect(lambda state: self._toggleModelVisibility(model, state))
|
||||
self.name_input = QLineEdit(itemText)
|
||||
|
||||
self.name_input.returnPressed.connect(
|
||||
@ -685,14 +691,14 @@ class PropertyPanelManager:
|
||||
self.name_group.setLayout(name_layout)
|
||||
self._propertyLayout.addWidget(self.name_group)
|
||||
|
||||
if model:
|
||||
try:
|
||||
self.active_check.stateChanged.disconnect()
|
||||
except TypeError:
|
||||
pass
|
||||
self.active_check.stateChanged.connect(
|
||||
lambda state, m=model: self._setUserVisible(m, state == Qt.Checked)
|
||||
)
|
||||
# if model:
|
||||
# try:
|
||||
# self.active_check.stateChanged.disconnect()
|
||||
# except TypeError:
|
||||
# pass
|
||||
# self.active_check.stateChanged.connect(
|
||||
# lambda state, m=model: self._setUserVisible(m, state == Qt.Checked)
|
||||
# )
|
||||
# nameLabel = QLabel("名称:")
|
||||
# nameEdit = QLineEdit(itemText)
|
||||
# self._propertyLayout.addRow(nameLabel, nameEdit)
|
||||
@ -710,6 +716,8 @@ class PropertyPanelManager:
|
||||
self.updateLightPropertyPanel(model)
|
||||
elif model:
|
||||
self._updateModelPropertyPanel(model)
|
||||
# 启动变换监控
|
||||
self.startTransformMonitoring(model)
|
||||
|
||||
self._propertyLayout.addStretch()
|
||||
|
||||
@ -1086,6 +1094,9 @@ class PropertyPanelManager:
|
||||
|
||||
def _cleanupAllReferences(self):
|
||||
"""清理所有控件引用"""
|
||||
# 停止变换监控
|
||||
self.stopTransformMonitoring()
|
||||
|
||||
# 清理变换控件引用
|
||||
self._cleanupTransformControls()
|
||||
|
||||
@ -1126,6 +1137,15 @@ class PropertyPanelManager:
|
||||
node.setPythonTag("user_visible", visible)
|
||||
self._syncEffectiveVisibility(node)
|
||||
|
||||
def _setUserVisible_light(self, node, visible):
|
||||
"""设置用户可见性状态"""
|
||||
try:
|
||||
# 保存可见性状态
|
||||
node.setPythonTag("user_visible", visible)
|
||||
|
||||
except Exception as e:
|
||||
print(f"设置用户可见性失败: {e}")
|
||||
|
||||
def _syncEffectiveVisibility(self, start_node):
|
||||
"""广度优先,确保父隐藏则子一定隐藏"""
|
||||
# 获取起始节点的父节点
|
||||
@ -1164,16 +1184,32 @@ class PropertyPanelManager:
|
||||
def _toggleModelVisibility(self, model, state):
|
||||
"""切换模型可见性状态"""
|
||||
try:
|
||||
# 用我们自己维护的可见性接口,而不是直接 show/hide
|
||||
visible = (state == Qt.Checked)
|
||||
self._setUserVisible(model, visible)
|
||||
# 特殊处理灯光对象
|
||||
scene_manager = None
|
||||
if hasattr(self.world, 'scene_manager'):
|
||||
scene_manager = self.world.scene_manager
|
||||
|
||||
collision_nodes = model.findAllMatches("**/modelCollision_*")
|
||||
for collision_node in collision_nodes:
|
||||
collision_node.hide()
|
||||
if scene_manager and hasattr(scene_manager, 'isLightObject'):
|
||||
is_light = scene_manager.isLightObject(model)
|
||||
|
||||
if is_light:
|
||||
visible = (state == Qt.Checked)
|
||||
self._setUserVisible_light(model, visible)
|
||||
if hasattr(scene_manager, 'toggleLightVisibility'):
|
||||
scene_manager.toggleLightVisibility(model, visible)
|
||||
return # 关键:这里必须return,避免执行下面的普通模型逻辑
|
||||
else:
|
||||
visible = (state == Qt.Checked)
|
||||
self._setUserVisible(model, visible)
|
||||
|
||||
collision_nodes = model.findAllMatches("**/modelCollision_*")
|
||||
for collision_node in collision_nodes:
|
||||
collision_node.hide()
|
||||
|
||||
except Exception as e:
|
||||
print(f"切换模型可见性失败: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def refreshModelValues(self, nodePath):
|
||||
"""刷新模型值显示"""
|
||||
@ -1199,6 +1235,67 @@ class PropertyPanelManager:
|
||||
except Exception as e:
|
||||
print(f"刷新模型值显示失败: {e}")
|
||||
|
||||
def startTransformMonitoring(self, nodePath):
|
||||
"""开始监控节点的变换变化"""
|
||||
# 如果已有监控器在运行,先停止它
|
||||
self.stopTransformMonitoring()
|
||||
|
||||
# 保存初始变换值
|
||||
self._saveCurrentTransformValues(nodePath)
|
||||
|
||||
# 创建并启动定时器
|
||||
self._transform_monitor_timer = QTimer()
|
||||
self._transform_monitor_timer.timeout.connect(lambda: self._checkTransformChanges(nodePath))
|
||||
self._transform_monitor_timer.start(100) # 每100毫秒检查一次
|
||||
|
||||
def stopTransformMonitoring(self):
|
||||
"""停止监控节点的变换变化"""
|
||||
if self._transform_monitor_timer:
|
||||
self._transform_monitor_timer.stop()
|
||||
self._transform_monitor_timer.deleteLater()
|
||||
self._transform_monitor_timer = None
|
||||
|
||||
# 清除保存的变换值
|
||||
self._last_transform_values.clear()
|
||||
|
||||
def _saveCurrentTransformValues(self, nodePath):
|
||||
"""保存当前节点的变换值"""
|
||||
try:
|
||||
pos = nodePath.getPos()
|
||||
hpr = nodePath.getHpr()
|
||||
scale = nodePath.getScale()
|
||||
|
||||
self._last_transform_values = {
|
||||
'pos': (pos.getX(), pos.getY(), pos.getZ()),
|
||||
'hpr': (hpr.getX(), hpr.getY(), hpr.getZ()),
|
||||
'scale': (scale.getX(), scale.getY(), scale.getZ())
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"保存变换值失败: {e}")
|
||||
|
||||
def _checkTransformChanges(self, nodePath):
|
||||
"""检查节点变换是否发生变化"""
|
||||
try:
|
||||
# 获取当前变换值
|
||||
pos = nodePath.getPos()
|
||||
hpr = nodePath.getHpr()
|
||||
scale = nodePath.getScale()
|
||||
|
||||
current_values = {
|
||||
'pos': (pos.getX(), pos.getY(), pos.getZ()),
|
||||
'hpr': (hpr.getX(), hpr.getY(), hpr.getZ()),
|
||||
'scale': (scale.getX(), scale.getY(), scale.getZ())
|
||||
}
|
||||
|
||||
# 比较变换值是否发生变化
|
||||
if current_values != self._last_transform_values:
|
||||
# 变换已更改,刷新属性面板
|
||||
self.refreshModelValues(nodePath)
|
||||
# 更新保存的变换值
|
||||
self._last_transform_values = current_values
|
||||
except Exception as e:
|
||||
print(f"检查变换变化失败: {e}")
|
||||
|
||||
def _refreshGUIElementValues(self, gui_element):
|
||||
"""刷新GUI元素值显示"""
|
||||
try:
|
||||
@ -4670,10 +4767,8 @@ class PropertyPanelManager:
|
||||
|
||||
is_first_load = not video_screen.hasTag("video_path") or not video_screen.getTag("video_path")
|
||||
|
||||
needs_second_call = False
|
||||
if is_first_load and not hasattr(self, '_first_load_processed'):
|
||||
needs_second_call = True
|
||||
self._first_load_processed = True
|
||||
# 确保之前的视频流已停止
|
||||
self._stop3DVideo(video_screen)
|
||||
|
||||
load_url_btn = None
|
||||
if hasattr(self, '_current_load_url_btn_3d'):
|
||||
@ -4706,9 +4801,6 @@ class PropertyPanelManager:
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
QApplication.processEvents()
|
||||
|
||||
# 停止之前可能正在播放的视频
|
||||
self._stop3DVideo(video_screen)
|
||||
|
||||
# 使用 OpenCV 打开视频流
|
||||
cap = cv2.VideoCapture(url)
|
||||
if not cap.isOpened():
|
||||
@ -4821,13 +4913,6 @@ class PropertyPanelManager:
|
||||
|
||||
print(f"✅ 开始在3D视频屏幕上播放网络视频流: {url}")
|
||||
|
||||
if needs_second_call:
|
||||
print("检测到首次加载,再次调用_loadVideoFromURLWithOpenCV_3D以确保正确显示")
|
||||
from PyQt5.QtCore import QTimer
|
||||
QTimer.singleShot(100, lambda: self._loadVideoFromURLWithOpenCV_3D(video_screen, url))
|
||||
QTimer.singleShot(200, lambda: setattr(self, '_first_load_processed', False) if hasattr(self,
|
||||
'_first_load_processed') else None)
|
||||
|
||||
# 恢复按钮状态
|
||||
update_button_text("加载URL")
|
||||
update_button_enabled(True)
|
||||
@ -5443,11 +5528,22 @@ class PropertyPanelManager:
|
||||
light_group = QGroupBox("光源属性")
|
||||
light_layout = QGridLayout()
|
||||
|
||||
current_energy = light_object.energy
|
||||
stored_energy = None
|
||||
|
||||
if current_energy == 0.0 and model.hasTag("stored_energy"):
|
||||
try:
|
||||
stored_energy = float(model.getTag("stored_energy"))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
display_energy = stored_energy if stored_energy is not None and stored_energy > 0 else current_energy
|
||||
|
||||
# 能量
|
||||
light_layout.addWidget(QLabel("能量:"), 0, 0)
|
||||
energySpinBox = QDoubleSpinBox()
|
||||
energySpinBox.setRange(0, 10000)
|
||||
energySpinBox.setValue(light_object.energy)
|
||||
energySpinBox.setValue(display_energy)
|
||||
energySpinBox.valueChanged.connect(lambda v: self._updateLightEnergy(light_object, v))
|
||||
light_layout.addWidget(energySpinBox, 0, 1, 1, 3)
|
||||
|
||||
@ -6299,7 +6395,7 @@ class PropertyPanelManager:
|
||||
"""应用漫反射贴图"""
|
||||
try:
|
||||
from RenderPipelineFile.rpcore.loader import RPLoader
|
||||
from panda3d.core import TextureStage
|
||||
from panda3d.core import TextureStage, TransparencyAttrib
|
||||
|
||||
# 加载纹理
|
||||
texture = RPLoader.load_texture(texture_path)
|
||||
@ -6309,10 +6405,19 @@ class PropertyPanelManager:
|
||||
if node and material:
|
||||
print(f"正在为节点 {node.getName()} 应用漫反射贴图")
|
||||
|
||||
# 检查纹理是否包含透明度信息
|
||||
has_alpha = False
|
||||
# 检查纹理格式
|
||||
format_name = str(texture.getFormat())
|
||||
if 'alpha' in format_name.lower() or 'rgba' in format_name.lower():
|
||||
has_alpha = True
|
||||
|
||||
print(f"纹理格式: {texture.getFormat()}, 包含透明通道: {has_alpha}")
|
||||
|
||||
# 检查是否有金属性贴图,选择合适的PBR效果
|
||||
print("🔧 检查金属性贴图并选择合适的PBR效果...")
|
||||
has_metallic = self._hasMetallicTexture(node)
|
||||
needs_alpha = self._needsAlphaTesting(node)
|
||||
needs_alpha = self._needsAlphaTesting(node) or has_alpha
|
||||
|
||||
if has_metallic:
|
||||
print("✅ 检测到金属性贴图,使用支持金属性的PBR效果")
|
||||
@ -6360,6 +6465,15 @@ class PropertyPanelManager:
|
||||
node.setTexture(diffuse_stage, texture)
|
||||
print("漫反射贴图已应用到p3d_Texture0槽")
|
||||
|
||||
# 如果纹理包含透明度,启用透明度渲染
|
||||
if has_alpha:
|
||||
print("检测到透明纹理,启用透明度渲染")
|
||||
node.setTransparency(TransparencyAttrib.MAlpha)
|
||||
node.setDepthWrite(False) # 透明物体通常不写入深度缓冲区
|
||||
else:
|
||||
# 确保关闭透明度(避免之前设置的影响)
|
||||
node.setTransparency(TransparencyAttrib.MNone)
|
||||
|
||||
# 调试信息:显示当前纹理阶段
|
||||
print("=== 漫反射贴图应用后的纹理阶段信息 ===")
|
||||
all_stages = node.findAllTextureStages()
|
||||
@ -6412,6 +6526,7 @@ class PropertyPanelManager:
|
||||
has_diffuse_texture = True
|
||||
print(f" 🔍 发现现有漫反射贴图: {tex.getName()}")
|
||||
|
||||
|
||||
# 如果没有漫反射贴图,必须创建白色纹理,否则法线映射会失效
|
||||
if not has_diffuse_texture:
|
||||
print("⚠️ 没有漫反射贴图,创建白色纹理确保法线映射正常工作...")
|
||||
@ -8746,12 +8861,12 @@ class PropertyPanelManager:
|
||||
if hasattr(setting_handle, 'curves') and setting_handle.curves:
|
||||
# 清除现有的控制点,设置单一值
|
||||
setting_handle.curves[0].set_single_value(normalized_value)
|
||||
print(f"✅ 更新Day Time设置: {plugin_name}.{setting_name} = {value} (归一化: {normalized_value:.3f})")
|
||||
#print(f"✅ 更新Day Time设置: {plugin_name}.{setting_name} = {value} (归一化: {normalized_value:.3f})")
|
||||
|
||||
# 保存设置到配置文件
|
||||
try:
|
||||
plugin_mgr.save_daytime_overrides("/$$rpconfig/daytime.yaml")
|
||||
print("✅ Day Time设置已保存到配置文件")
|
||||
#print("✅ Day Time设置已保存到配置文件")
|
||||
except Exception as e:
|
||||
print(f"⚠️ 保存配置文件失败: {e}")
|
||||
|
||||
@ -8759,7 +8874,7 @@ class PropertyPanelManager:
|
||||
try:
|
||||
from RenderPipelineFile.rpcore.util.network_communication import NetworkCommunication
|
||||
NetworkCommunication.send_async(NetworkCommunication.DAYTIME_PORT, "loadconf")
|
||||
print("✅ 已通知Day Time Editor重新加载配置")
|
||||
#print("✅ 已通知Day Time Editor重新加载配置")
|
||||
except Exception as e:
|
||||
print(f"⚠️ 通知Day Time Editor失败: {e}")
|
||||
|
||||
@ -9054,22 +9169,98 @@ class PropertyPanelManager:
|
||||
def _getActor(self, origin_model):
|
||||
if origin_model in self._actor_cache:
|
||||
return self._actor_cache[origin_model]
|
||||
|
||||
# 首先检查是否可以直接从内存中的模型创建Actor
|
||||
if origin_model.hasTag("can_create_actor_from_memory") and origin_model.getTag("can_create_actor_from_memory").lower() == "true":
|
||||
try:
|
||||
print(f"[Actor加载] 直接从内存模型创建Actor: {origin_model.getName()}")
|
||||
# 直接从内存中的模型创建Actor
|
||||
test_actor = Actor(origin_model)
|
||||
anims = test_actor.getAnimNames()
|
||||
test_actor.reparentTo(self.world.render)
|
||||
self._actor_cache[origin_model] = test_actor
|
||||
print(f"[Actor加载] 内存创建检测到动画: {anims}")
|
||||
if anims:
|
||||
return test_actor
|
||||
else:
|
||||
test_actor.cleanup()
|
||||
test_actor.removeNode()
|
||||
except Exception as e:
|
||||
print(f"从内存模型创建Actor失败: {e}")
|
||||
|
||||
# 如果不能直接从内存创建,再尝试通过文件路径加载
|
||||
filepath = origin_model.getTag("model_path")
|
||||
if not filepath:
|
||||
return None
|
||||
|
||||
print(f"[Actor加载] 尝试加载: {filepath}")
|
||||
|
||||
# 处理跨平台路径问题
|
||||
import os
|
||||
# 检查路径是否有效,如果无效则尝试修复
|
||||
if not os.path.exists(filepath):
|
||||
original_filepath = filepath
|
||||
# 尝试多种修复策略
|
||||
fixed = False
|
||||
|
||||
# 策略1: 处理Linux风格路径在Windows上的问题
|
||||
if filepath.startswith('/') and ':' not in filepath:
|
||||
# 提取文件名并尝试在当前目录查找
|
||||
filename = os.path.basename(filepath)
|
||||
potential_path = os.path.join(os.getcwd(), filename)
|
||||
if os.path.exists(potential_path):
|
||||
filepath = potential_path
|
||||
fixed = True
|
||||
|
||||
# 策略2: 处理路径分隔符问题
|
||||
if not fixed:
|
||||
# 尝试规范化路径
|
||||
normalized_path = os.path.normpath(filepath)
|
||||
if os.path.exists(normalized_path):
|
||||
filepath = normalized_path
|
||||
fixed = True
|
||||
|
||||
# 策略3: 在Resources目录中查找
|
||||
if not fixed:
|
||||
# 尝试在Resources目录中查找文件
|
||||
resources_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "Resources")
|
||||
filename = os.path.basename(filepath)
|
||||
potential_path = os.path.join(resources_path, filename)
|
||||
if os.path.exists(potential_path):
|
||||
filepath = potential_path
|
||||
fixed = True
|
||||
|
||||
if fixed:
|
||||
print(f"路径修复: {original_filepath} -> {filepath}")
|
||||
# 更新模型标签
|
||||
origin_model.setTag("model_path", filepath)
|
||||
else:
|
||||
print(f"[警告] 模型文件不存在: {filepath}")
|
||||
return None
|
||||
|
||||
# 检查是否是 FBX 文件,如果是,使用专门的 FBX 动画加载器
|
||||
if filepath.lower().endswith('.fbx'):
|
||||
return self._createFBXActor(origin_model, filepath)
|
||||
pass
|
||||
#return self._createFBXActor(origin_model, filepath)
|
||||
|
||||
# 其他格式使用标准 Actor 加载
|
||||
try:
|
||||
import gltf
|
||||
print(f"[GLTF加载] 尝试加载: {filepath}")
|
||||
from panda3d.core import Filename
|
||||
|
||||
# 将Panda3D路径转换为操作系统特定路径
|
||||
panda_filename = Filename(filepath)
|
||||
os_specific_path = panda_filename.to_os_specific()
|
||||
print(f"[路径转换] {filepath} -> {os_specific_path}")
|
||||
|
||||
print(f"[GLTF加载] 尝试加载: {os_specific_path}")
|
||||
|
||||
# 使用明确的设置确保动画被加载
|
||||
gltf_settings = gltf.GltfSettings(skip_animations=False)
|
||||
# test_actor=Actor(NodePath(gltf._loader.GltfLoader.load_file(filepath,None)))
|
||||
test_actor = Actor(NodePath(gltf.load_model(filepath, None)))
|
||||
model_root = gltf.load_model(os_specific_path, gltf_settings)
|
||||
model_node = NodePath(model_root)
|
||||
test_actor = Actor(model_node)
|
||||
anims = test_actor.getAnimNames()
|
||||
test_actor.reparentTo(self.world.render)
|
||||
self._actor_cache[origin_model] = test_actor
|
||||
@ -9711,6 +9902,12 @@ except Exception as e:
|
||||
collision_group.setLayout(collision_layout)
|
||||
self._propertyLayout.addWidget(collision_group)
|
||||
|
||||
# 同步一次状态,确保主按钮与可见性按钮齐全
|
||||
try:
|
||||
self._updateCollisionPanelState(model)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
print(f"创建碰撞面板失败: {e}")
|
||||
import traceback
|
||||
@ -10065,8 +10262,9 @@ except Exception as e:
|
||||
collision_np.show()
|
||||
print(f"显示碰撞:{model.getName()}")
|
||||
|
||||
# 立即更新按钮状态
|
||||
# 立即更新按钮状态,并同步更新面板(确保缺失主按钮时补建)
|
||||
self._updateCollisionVisibilityButton(model)
|
||||
self._updateCollisionPanelState(model)
|
||||
|
||||
except Exception as e:
|
||||
print(f"切换碰撞可见性失败: {e}")
|
||||
@ -10274,26 +10472,18 @@ except Exception as e:
|
||||
has_collision = self._hasCollision(model)
|
||||
print(f"模型 {model.getName()} 是否有碰撞体: {has_collision}-------------------------------------------------")
|
||||
|
||||
# 更新状态徽章(使用固定宽度)
|
||||
if has_collision:
|
||||
new_badge = self.createFixedStatusBadge("已启用", "green")
|
||||
else:
|
||||
new_badge = self.createFixedStatusBadge("未启用", "red")
|
||||
|
||||
# 替换旧的徽章
|
||||
old_badge = self.collision_status_badge
|
||||
parent_layout = old_badge.parent().layout()
|
||||
if parent_layout:
|
||||
# 找到旧徽章在布局中的位置
|
||||
for i in range(parent_layout.count()):
|
||||
item = parent_layout.itemAt(i)
|
||||
if item and item.widget() == old_badge:
|
||||
# 移除旧徽章并添加新徽章
|
||||
parent_layout.removeWidget(old_badge)
|
||||
old_badge.deleteLater()
|
||||
parent_layout.addWidget(new_badge, 0, 0, 1, 1) # 状态徽章在第0行第1列
|
||||
self.collision_status_badge = new_badge
|
||||
break
|
||||
# 更新状态徽章(直接修改现有控件,避免布局冲突)
|
||||
if hasattr(self, 'collision_status_badge') and self.collision_status_badge:
|
||||
if has_collision:
|
||||
self.collision_status_badge.setText("已启用")
|
||||
# 使用固定宽度的绿色样式,保持尺寸一致
|
||||
self.collision_status_badge.setStyleSheet(self.badge_style_green_fixed)
|
||||
else:
|
||||
self.collision_status_badge.setText("未启用")
|
||||
# 使用固定宽度的红色样式,保持尺寸一致
|
||||
self.collision_status_badge.setStyleSheet(self.badge_style_red_fixed)
|
||||
# 触发重绘,确保立即可见
|
||||
self.collision_status_badge.update()
|
||||
|
||||
if has_collision:
|
||||
# 有碰撞:显示移除按钮,下拉框变为只读并显示当前类型
|
||||
@ -10309,6 +10499,18 @@ except Exception as e:
|
||||
except:
|
||||
pass
|
||||
self.collision_button.clicked.connect(lambda: self._removeCollisionAndUpdate(model))
|
||||
else:
|
||||
# 若不存在主按钮,则创建“移除碰撞”按钮并加入布局
|
||||
try:
|
||||
self.collision_button = self.createModernButton("移除碰撞")
|
||||
self.collision_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||
self.collision_button.setStyleSheet(self._collision_button_style())
|
||||
self.collision_button.clicked.connect(lambda: self._removeCollisionAndUpdate(model))
|
||||
if hasattr(self, 'collision_layout') and self.collision_layout is not None:
|
||||
row = self.collision_layout.rowCount()
|
||||
self.collision_layout.addWidget(self.collision_button, row, 0, 1, 4)
|
||||
except Exception as _e:
|
||||
print(f"创建移除碰撞按钮失败: {_e}")
|
||||
|
||||
# 获取并显示当前碰撞类型,设置为只读
|
||||
current_shape = self._getCurrentCollisionShape(model)
|
||||
@ -10328,6 +10530,13 @@ except Exception as e:
|
||||
self.collision_visibility_button.setVisible(True)
|
||||
self._updateCollisionVisibilityButton(model)
|
||||
|
||||
# 确保按钮顺序:可见性按钮在上,主按钮在下
|
||||
if hasattr(self, 'collision_layout'):
|
||||
try:
|
||||
self._repositionButtons(self.collision_layout.rowCount())
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
print(f"碰撞面板状态更新:有碰撞 - {current_shape}")
|
||||
|
||||
else:
|
||||
@ -10343,6 +10552,18 @@ except Exception as e:
|
||||
except:
|
||||
pass
|
||||
self.collision_button.clicked.connect(lambda: self._addCollisionAndUpdate(model))
|
||||
else:
|
||||
# 若不存在主按钮,则创建“添加碰撞”按钮并加入布局
|
||||
try:
|
||||
self.collision_button = self.createModernButton("添加碰撞")
|
||||
self.collision_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||
self.collision_button.setStyleSheet(self._collision_button_style())
|
||||
self.collision_button.clicked.connect(lambda: self._addCollisionAndUpdate(model))
|
||||
if hasattr(self, 'collision_layout') and self.collision_layout is not None:
|
||||
row = self.collision_layout.rowCount()
|
||||
self.collision_layout.addWidget(self.collision_button, row, 0, 1, 4)
|
||||
except Exception as _e:
|
||||
print(f"创建添加碰撞按钮失败: {_e}")
|
||||
|
||||
# 恢复为可编辑状态
|
||||
self.collision_shape_combo.setEnabled(True)
|
||||
@ -10356,6 +10577,13 @@ except Exception as e:
|
||||
if hasattr(self, 'collision_visibility_button'):
|
||||
self.collision_visibility_button.setVisible(False)
|
||||
|
||||
# 确保按钮顺序:主按钮位于底部
|
||||
if hasattr(self, 'collision_layout'):
|
||||
try:
|
||||
self._repositionButtons(self.collision_layout.rowCount())
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
print(f"碰撞面板状态更新:无碰撞 - 可编辑")
|
||||
|
||||
except Exception as e:
|
||||
@ -11018,13 +11246,24 @@ except Exception as e:
|
||||
layout = self.collision_layout
|
||||
is_collision_visible = self._isCollisionVisible(model)
|
||||
|
||||
# 找到合适的行位置
|
||||
# 放在当前最后一行
|
||||
current_row = layout.rowCount()
|
||||
|
||||
self.collision_visibility_button = QPushButton("隐藏碰撞" if is_collision_visible else "显示碰撞")
|
||||
self.collision_visibility_button.setStyleSheet(self._collision_button_style())
|
||||
self.collision_visibility_button.clicked.connect(lambda: self._toggleCollisionVisibility(model))
|
||||
layout.addWidget(self.collision_visibility_button, current_row - 1, 0, 1, 4)
|
||||
layout.addWidget(self.collision_visibility_button, current_row, 0, 1, 4)
|
||||
|
||||
# 确保存在主按钮(有碰撞时应显示移除碰撞)
|
||||
if self._hasCollision(model) and not hasattr(self, 'collision_button'):
|
||||
try:
|
||||
self.collision_button = self.createModernButton("移除碰撞")
|
||||
self.collision_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||
self.collision_button.setStyleSheet(self._collision_button_style())
|
||||
self.collision_button.clicked.connect(lambda: self._removeCollisionAndUpdate(model))
|
||||
layout.addWidget(self.collision_button, current_row + 1, 0, 1, 4)
|
||||
except Exception as _e:
|
||||
print(f"在可见性按钮后创建移除碰撞按钮失败: {_e}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"添加可见性按钮失败: {e}")
|
||||
@ -11035,22 +11274,39 @@ except Exception as e:
|
||||
if hasattr(self, 'collision_layout'):
|
||||
layout = self.collision_layout
|
||||
|
||||
# 移动可见性按钮
|
||||
if hasattr(self, 'collision_visibility_button'):
|
||||
layout.addWidget(self.collision_visibility_button, new_row, 0, 1, 4)
|
||||
new_row += 1
|
||||
def _remove_if_present(w):
|
||||
try:
|
||||
if not w:
|
||||
return
|
||||
# 从布局中移除该控件(如果已存在)
|
||||
for i in range(layout.count()):
|
||||
item = layout.itemAt(i)
|
||||
if item and item.widget() is w:
|
||||
layout.removeWidget(w)
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 移动主按钮
|
||||
if hasattr(self, 'collision_button'):
|
||||
layout.addWidget(self.collision_button, new_row, 0, 1, 4)
|
||||
# 计算底部行
|
||||
bottom_row = layout.rowCount()
|
||||
|
||||
# 按固定顺序重新放置:先可见性按钮,再主按钮
|
||||
if hasattr(self, 'collision_visibility_button') and self.collision_visibility_button:
|
||||
_remove_if_present(self.collision_visibility_button)
|
||||
layout.addWidget(self.collision_visibility_button, bottom_row, 0, 1, 4)
|
||||
bottom_row += 1
|
||||
|
||||
if hasattr(self, 'collision_button') and self.collision_button:
|
||||
_remove_if_present(self.collision_button)
|
||||
layout.addWidget(self.collision_button, bottom_row, 0, 1, 4)
|
||||
|
||||
except Exception as e:
|
||||
print(f"重新定位按钮失败: {e}")
|
||||
|
||||
def _hideCollisionParameterControls(self):
|
||||
"""隐藏碰撞参数控件(保留按钮)"""
|
||||
"""隐藏并移除碰撞参数控件与其所在的行(保留状态/形状/按钮行)"""
|
||||
try:
|
||||
# 清理属性引用,但保留按钮
|
||||
# 1) 先清理对象属性引用,避免残留信号
|
||||
param_attrs = [
|
||||
'collision_pos_x', 'collision_pos_y', 'collision_pos_z',
|
||||
'collision_radius',
|
||||
@ -11058,47 +11314,72 @@ except Exception as e:
|
||||
'collision_capsule_radius', 'collision_capsule_height',
|
||||
'collision_normal_x', 'collision_normal_y', 'collision_normal_z'
|
||||
]
|
||||
|
||||
# 隐藏并删除参数控件
|
||||
for attr in param_attrs:
|
||||
if hasattr(self, attr):
|
||||
widget = getattr(self, attr)
|
||||
if widget:
|
||||
widget.setVisible(False)
|
||||
widget.setParent(None)
|
||||
widget.deleteLater()
|
||||
try:
|
||||
if widget:
|
||||
widget.setParent(None)
|
||||
widget.deleteLater()
|
||||
except Exception:
|
||||
pass
|
||||
delattr(self, attr)
|
||||
|
||||
# 同时清理可能的标签控件
|
||||
if hasattr(self, 'collision_layout'):
|
||||
# 2) 深度移除布局中第2行(索引>=2)之后的所有参数相关项,保留按钮
|
||||
if hasattr(self, 'collision_layout') and self.collision_layout is not None:
|
||||
layout = self.collision_layout
|
||||
|
||||
# 收集需要移除的控件(不包括基本控件和按钮)
|
||||
widgets_to_remove = []
|
||||
def _remove_layout_recursive(q_layout):
|
||||
try:
|
||||
while q_layout.count():
|
||||
child = q_layout.takeAt(0)
|
||||
if child.widget():
|
||||
w = child.widget()
|
||||
w.setParent(None)
|
||||
w.deleteLater()
|
||||
elif child.layout():
|
||||
_remove_layout_recursive(child.layout())
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
for i in range(layout.rowCount()):
|
||||
if i >= 2: # 从第3行开始检查
|
||||
for j in range(layout.columnCount()):
|
||||
item = layout.itemAtPosition(i, j)
|
||||
if item:
|
||||
widget = item.widget()
|
||||
if widget and hasattr(widget, 'text'):
|
||||
# 检查是否是参数相关的标签
|
||||
text = widget.text()
|
||||
if any(keyword in text for keyword in
|
||||
['位置偏移', 'X:', 'Y:', 'Z:', '半径:', '尺寸:', '宽度:', '长度:', '高度:',
|
||||
'法向量:', 'Nx:', 'Ny:', 'Nz:']):
|
||||
widgets_to_remove.append(widget)
|
||||
row_count = layout.rowCount()
|
||||
col_count = layout.columnCount()
|
||||
# 从参数区域开始清理(行索引2及以后),但跳过我们要保留的按钮
|
||||
for i in range(2, row_count):
|
||||
for j in range(0, col_count):
|
||||
item = layout.itemAtPosition(i, j)
|
||||
if not item:
|
||||
continue
|
||||
# 若是按钮,且是保留的按钮,则跳过
|
||||
w = item.widget()
|
||||
if w is not None:
|
||||
try:
|
||||
if (hasattr(self, 'collision_button') and w == self.collision_button) or (hasattr(self, 'collision_visibility_button') and w == self.collision_visibility_button):
|
||||
continue
|
||||
except Exception:
|
||||
pass
|
||||
layout.removeWidget(w)
|
||||
w.setParent(None)
|
||||
w.deleteLater()
|
||||
elif item.layout():
|
||||
# 移除嵌套布局(包含标签与输入框)
|
||||
nested = item.layout()
|
||||
_remove_layout_recursive(nested)
|
||||
layout.removeItem(nested)
|
||||
|
||||
# 移除参数标签
|
||||
for widget in widgets_to_remove:
|
||||
widget.setVisible(False)
|
||||
widget.setParent(None)
|
||||
widget.deleteLater()
|
||||
# 尝试把保留的按钮移动到参数区域第一行(行2)下方,保持整洁
|
||||
try:
|
||||
next_row = 2
|
||||
if hasattr(self, 'collision_visibility_button'):
|
||||
self.collision_visibility_button.setVisible(False)
|
||||
if hasattr(self, 'collision_button') and self.collision_button is not None:
|
||||
layout.addWidget(self.collision_button, next_row, 0, 1, 4)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
print("隐藏碰撞参数控件完成(保留按钮)")
|
||||
print("隐藏碰撞参数控件完成(仅保留状态、形状与按钮)")
|
||||
|
||||
except Exception as e:
|
||||
print(f"隐藏碰撞参数控件失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
traceback.print_exc()
|
||||
|
||||
@ -20,7 +20,7 @@ from PyQt5.sip import wrapinstance
|
||||
from direct.showbase.ShowBaseGlobal import aspect2d
|
||||
from panda3d.core import ModelRoot, NodePath, CollisionNode
|
||||
|
||||
from QPanda3D.QPanda3DWidget import QPanda3DWidget
|
||||
from QMeta3D.QMeta3DWidget import QMeta3DWidget
|
||||
from scene import util
|
||||
from ui.icon_manager import get_icon_manager
|
||||
|
||||
@ -456,7 +456,7 @@ class NewProjectDialog(QDialog):
|
||||
|
||||
self.accept()
|
||||
|
||||
class CustomPanda3DWidget(QPanda3DWidget):
|
||||
class CustomMeta3DWidget(QMeta3DWidget):
|
||||
"""自定义Panda3D显示部件"""
|
||||
|
||||
def __init__(self, world, parent=None):
|
||||
@ -4196,7 +4196,7 @@ class CustomTreeWidget(QTreeWidget):
|
||||
def _createSpotLightNode(self, parent_node, parent_item):
|
||||
"""创建聚光灯节点"""
|
||||
from RenderPipelineFile.rpcore import SpotLight
|
||||
from QPanda3D.Panda3DWorld import get_render_pipeline
|
||||
from QMeta3D.Meta3DWorld import get_render_pipeline
|
||||
from panda3d.core import Vec3, NodePath
|
||||
|
||||
try:
|
||||
@ -4252,7 +4252,7 @@ class CustomTreeWidget(QTreeWidget):
|
||||
def _createPointLightNode(self, parent_node, parent_item):
|
||||
"""创建点光源节点"""
|
||||
from RenderPipelineFile.rpcore import PointLight
|
||||
from QPanda3D.Panda3DWorld import get_render_pipeline
|
||||
from QMeta3D.Meta3DWorld import get_render_pipeline
|
||||
from panda3d.core import Vec3, NodePath
|
||||
|
||||
try:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user