Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
00e452ede6
|
|
@ -355,6 +355,23 @@ jobs:
|
|||
rmdir panda3d-1.10.14
|
||||
(cd thirdparty/darwin-libs-a && rm -rf rocket)
|
||||
|
||||
- name: Set up Python 3.12
|
||||
if: matrix.os != 'windows-2019'
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Build Python 3.12
|
||||
if: matrix.os != 'windows-2019'
|
||||
shell: bash
|
||||
run: |
|
||||
python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10
|
||||
- name: Test Python 3.12
|
||||
if: matrix.os != 'windows-2019'
|
||||
shell: bash
|
||||
run: |
|
||||
python -m pip install -r requirements-test.txt
|
||||
PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
|
||||
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -2650,11 +2650,11 @@ class main(wx.Frame):
|
|||
for inputFile in inputs:
|
||||
if (inputFile != ''):
|
||||
inputFilename = inputFile.split('\\')[-1]
|
||||
print "Compare: ", inFile, filename, inputFile, inputFilename
|
||||
print("Compare: ", inFile, filename, inputFile, inputFilename)
|
||||
if inputFilename == filename:
|
||||
inputTime = os.path.getmtime(inputFile)
|
||||
outputTime = os.path.getmtime(inFile)
|
||||
print "Matched: ", (inputTime > outputTime)
|
||||
print("Matched: ", (inputTime > outputTime))
|
||||
inputChanged = (inputTime > outputTime)
|
||||
break
|
||||
'''
|
||||
|
|
@ -2848,7 +2848,7 @@ class main(wx.Frame):
|
|||
|
||||
except ValueError:
|
||||
return
|
||||
#print self.batchList
|
||||
#print(self.batchList)
|
||||
|
||||
def OnBatchItemEdit(self, event):
|
||||
selectedItemId = self.batchTree.GetSelections()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from distutils.core import setup
|
||||
from setuptools import setup
|
||||
import py2exe
|
||||
|
||||
setup(console=['Panda3DToolsGUI.py'])
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
DirectNotify module: this module contains the DirectNotify class
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from panda3d.core import StreamWriter
|
||||
|
||||
from . import Notifier
|
||||
from . import Logger
|
||||
|
||||
|
|
@ -12,39 +16,39 @@ class DirectNotify:
|
|||
mulitple notify categories via a dictionary of Notifiers.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
"""
|
||||
DirectNotify class keeps a dictionary of Notfiers
|
||||
"""
|
||||
self.__categories = {}
|
||||
self.__categories: dict[str, Notifier.Notifier] = {}
|
||||
# create a default log file
|
||||
self.logger = Logger.Logger()
|
||||
|
||||
# This will get filled in later by ShowBase.py with a
|
||||
# C++-level StreamWriter object for writing to standard
|
||||
# output.
|
||||
self.streamWriter = None
|
||||
self.streamWriter: StreamWriter | None = None
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""
|
||||
Print handling routine
|
||||
"""
|
||||
return "DirectNotify categories: %s" % (self.__categories)
|
||||
|
||||
#getters and setters
|
||||
def getCategories(self):
|
||||
def getCategories(self) -> list[str]:
|
||||
"""
|
||||
Return list of category dictionary keys
|
||||
"""
|
||||
return list(self.__categories.keys())
|
||||
|
||||
def getCategory(self, categoryName):
|
||||
def getCategory(self, categoryName: str) -> Notifier.Notifier | None:
|
||||
"""getCategory(self, string)
|
||||
Return the category with given name if present, None otherwise
|
||||
"""
|
||||
return self.__categories.get(categoryName, None)
|
||||
|
||||
def newCategory(self, categoryName, logger=None):
|
||||
def newCategory(self, categoryName: str, logger: Logger.Logger | None = None) -> Notifier.Notifier:
|
||||
"""newCategory(self, string)
|
||||
Make a new notify category named categoryName. Return new category
|
||||
if no such category exists, else return existing category
|
||||
|
|
@ -52,9 +56,11 @@ class DirectNotify:
|
|||
if categoryName not in self.__categories:
|
||||
self.__categories[categoryName] = Notifier.Notifier(categoryName, logger)
|
||||
self.setDconfigLevel(categoryName)
|
||||
return self.getCategory(categoryName)
|
||||
notifier = self.getCategory(categoryName)
|
||||
assert notifier is not None
|
||||
return notifier
|
||||
|
||||
def setDconfigLevel(self, categoryName):
|
||||
def setDconfigLevel(self, categoryName: str) -> None:
|
||||
"""
|
||||
Check to see if this category has a dconfig variable
|
||||
to set the notify severity and then set that level. You cannot
|
||||
|
|
@ -77,40 +83,42 @@ class DirectNotify:
|
|||
level = 'error'
|
||||
|
||||
category = self.getCategory(categoryName)
|
||||
assert category is not None, f'failed to find category: {categoryName!r}'
|
||||
# Note - this print statement is making it difficult to
|
||||
# achieve "no output unless there's an error" operation - Josh
|
||||
# print ("Setting DirectNotify category: " + categoryName +
|
||||
# " to severity: " + level)
|
||||
if level == "error":
|
||||
category.setWarning(0)
|
||||
category.setInfo(0)
|
||||
category.setDebug(0)
|
||||
category.setWarning(False)
|
||||
category.setInfo(False)
|
||||
category.setDebug(False)
|
||||
elif level == "warning":
|
||||
category.setWarning(1)
|
||||
category.setInfo(0)
|
||||
category.setDebug(0)
|
||||
category.setWarning(True)
|
||||
category.setInfo(False)
|
||||
category.setDebug(False)
|
||||
elif level == "info":
|
||||
category.setWarning(1)
|
||||
category.setInfo(1)
|
||||
category.setDebug(0)
|
||||
category.setWarning(True)
|
||||
category.setInfo(True)
|
||||
category.setDebug(False)
|
||||
elif level == "debug":
|
||||
category.setWarning(1)
|
||||
category.setInfo(1)
|
||||
category.setDebug(1)
|
||||
category.setWarning(True)
|
||||
category.setInfo(True)
|
||||
category.setDebug(True)
|
||||
else:
|
||||
print("DirectNotify: unknown notify level: " + str(level)
|
||||
+ " for category: " + str(categoryName))
|
||||
|
||||
def setDconfigLevels(self):
|
||||
def setDconfigLevels(self) -> None:
|
||||
for categoryName in self.getCategories():
|
||||
self.setDconfigLevel(categoryName)
|
||||
|
||||
def setVerbose(self):
|
||||
def setVerbose(self) -> None:
|
||||
for categoryName in self.getCategories():
|
||||
category = self.getCategory(categoryName)
|
||||
category.setWarning(1)
|
||||
category.setInfo(1)
|
||||
category.setDebug(1)
|
||||
assert category is not None
|
||||
category.setWarning(True)
|
||||
category.setInfo(True)
|
||||
category.setDebug(True)
|
||||
|
||||
def popupControls(self, tl = None):
|
||||
# Don't use a regular import, to prevent ModuleFinder from picking
|
||||
|
|
@ -119,5 +127,5 @@ class DirectNotify:
|
|||
NotifyPanel = importlib.import_module('direct.tkpanels.NotifyPanel')
|
||||
NotifyPanel.NotifyPanel(self, tl)
|
||||
|
||||
def giveNotify(self,cls):
|
||||
def giveNotify(self, cls) -> None:
|
||||
cls.notify = self.newCategory(cls.__name__)
|
||||
|
|
|
|||
|
|
@ -1,27 +1,30 @@
|
|||
"""Logger module: contains the logger class which creates and writes
|
||||
data to log files on disk"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import time
|
||||
import math
|
||||
|
||||
|
||||
class Logger:
|
||||
def __init__(self, fileName="log"):
|
||||
def __init__(self, fileName: str = "log") -> None:
|
||||
"""
|
||||
Logger constructor
|
||||
"""
|
||||
self.__timeStamp = 1
|
||||
self.__timeStamp = True
|
||||
self.__startTime = 0.0
|
||||
self.__logFile = None
|
||||
self.__logFile: io.TextIOWrapper | None = None
|
||||
self.__logFileName = fileName
|
||||
|
||||
def setTimeStamp(self, enable):
|
||||
def setTimeStamp(self, enable: bool) -> None:
|
||||
"""
|
||||
Toggle time stamp printing with log entries on and off
|
||||
"""
|
||||
self.__timeStamp = enable
|
||||
|
||||
def getTimeStamp(self):
|
||||
def getTimeStamp(self) -> bool:
|
||||
"""
|
||||
Return whether or not we are printing time stamps with log entries
|
||||
"""
|
||||
|
|
@ -29,24 +32,25 @@ class Logger:
|
|||
|
||||
# logging control
|
||||
|
||||
def resetStartTime(self):
|
||||
def resetStartTime(self) -> None:
|
||||
"""
|
||||
Reset the start time of the log file for time stamps
|
||||
"""
|
||||
self.__startTime = time.time()
|
||||
|
||||
def log(self, entryString):
|
||||
def log(self, entryString: str) -> None:
|
||||
"""log(self, string)
|
||||
Print the given string to the log file"""
|
||||
if self.__logFile is None:
|
||||
self.__openLogFile()
|
||||
assert self.__logFile is not None
|
||||
if self.__timeStamp:
|
||||
self.__logFile.write(self.__getTimeStamp())
|
||||
self.__logFile.write(entryString + '\n')
|
||||
|
||||
# logging functions
|
||||
|
||||
def __openLogFile(self):
|
||||
def __openLogFile(self) -> None:
|
||||
"""
|
||||
Open a file for logging error/warning messages
|
||||
"""
|
||||
|
|
@ -56,14 +60,14 @@ class Logger:
|
|||
logFileName = self.__logFileName + "." + st
|
||||
self.__logFile = open(logFileName, "w")
|
||||
|
||||
def __closeLogFile(self):
|
||||
def __closeLogFile(self) -> None:
|
||||
"""
|
||||
Close the error/warning output file
|
||||
"""
|
||||
if self.__logFile is not None:
|
||||
self.__logFile.close()
|
||||
|
||||
def __getTimeStamp(self):
|
||||
def __getTimeStamp(self) -> str:
|
||||
"""
|
||||
Return the offset between current time and log file startTime
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -2,11 +2,16 @@
|
|||
Notifier module: contains methods for handling information output
|
||||
for the programmer/user
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .Logger import Logger
|
||||
from .LoggerGlobal import defaultLogger
|
||||
from direct.showbase import PythonUtil
|
||||
from panda3d.core import ConfigVariableBool, NotifyCategory, StreamWriter, Notify
|
||||
import time
|
||||
import sys
|
||||
from typing import NoReturn
|
||||
|
||||
|
||||
class NotifierException(Exception):
|
||||
|
|
@ -20,13 +25,13 @@ class Notifier:
|
|||
# messages instead of writing them to the console. This is
|
||||
# particularly useful for integrating the Python notify system
|
||||
# with the C++ notify system.
|
||||
streamWriter = None
|
||||
streamWriter: StreamWriter | None = None
|
||||
if ConfigVariableBool('notify-integrate', True):
|
||||
streamWriter = StreamWriter(Notify.out(), False)
|
||||
|
||||
showTime = ConfigVariableBool('notify-timestamp', False)
|
||||
|
||||
def __init__(self, name, logger=None):
|
||||
def __init__(self, name: str, logger: Logger | None = None) -> None:
|
||||
"""
|
||||
Parameters:
|
||||
name (str): a string name given to this Notifier instance.
|
||||
|
|
@ -42,12 +47,12 @@ class Notifier:
|
|||
self.__logger = logger
|
||||
|
||||
# Global default levels are initialized here
|
||||
self.__info = 1
|
||||
self.__warning = 1
|
||||
self.__debug = 0
|
||||
self.__logging = 0
|
||||
self.__info = True
|
||||
self.__warning = True
|
||||
self.__debug = False
|
||||
self.__logging = False
|
||||
|
||||
def setServerDelta(self, delta, timezone):
|
||||
def setServerDelta(self, delta: float, timezone: int) -> None:
|
||||
"""
|
||||
Call this method on any Notify object to globally change the
|
||||
timestamp printed for each line of all Notify objects.
|
||||
|
|
@ -65,7 +70,7 @@ class Notifier:
|
|||
|
||||
self.info("Notify clock adjusted by %s (and timezone adjusted by %s hours) to synchronize with server." % (PythonUtil.formatElapsedSeconds(delta), (time.timezone - timezone) / 3600))
|
||||
|
||||
def getTime(self):
|
||||
def getTime(self) -> str:
|
||||
"""
|
||||
Return the time as a string suitable for printing at the
|
||||
head of any notify message
|
||||
|
|
@ -74,14 +79,14 @@ class Notifier:
|
|||
# the task is out of focus on win32. time.clock doesn't have this problem.
|
||||
return time.strftime(":%m-%d-%Y %H:%M:%S ", time.localtime(time.time() + self.serverDelta))
|
||||
|
||||
def getOnlyTime(self):
|
||||
def getOnlyTime(self) -> str:
|
||||
"""
|
||||
Return the time as a string.
|
||||
The Only in the name is referring to not showing the date.
|
||||
"""
|
||||
return time.strftime("%H:%M:%S", time.localtime(time.time() + self.serverDelta))
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""
|
||||
Print handling routine
|
||||
"""
|
||||
|
|
@ -89,26 +94,26 @@ class Notifier:
|
|||
(self.__name, self.__info, self.__warning, self.__debug, self.__logging)
|
||||
|
||||
# Severity funcs
|
||||
def setSeverity(self, severity):
|
||||
def setSeverity(self, severity: int) -> None:
|
||||
from panda3d.core import NSDebug, NSInfo, NSWarning, NSError
|
||||
if severity >= NSError:
|
||||
self.setWarning(0)
|
||||
self.setInfo(0)
|
||||
self.setDebug(0)
|
||||
self.setWarning(False)
|
||||
self.setInfo(False)
|
||||
self.setDebug(False)
|
||||
elif severity == NSWarning:
|
||||
self.setWarning(1)
|
||||
self.setInfo(0)
|
||||
self.setDebug(0)
|
||||
self.setWarning(True)
|
||||
self.setInfo(False)
|
||||
self.setDebug(False)
|
||||
elif severity == NSInfo:
|
||||
self.setWarning(1)
|
||||
self.setInfo(1)
|
||||
self.setDebug(0)
|
||||
self.setWarning(True)
|
||||
self.setInfo(True)
|
||||
self.setDebug(False)
|
||||
elif severity <= NSDebug:
|
||||
self.setWarning(1)
|
||||
self.setInfo(1)
|
||||
self.setDebug(1)
|
||||
self.setWarning(True)
|
||||
self.setInfo(True)
|
||||
self.setDebug(True)
|
||||
|
||||
def getSeverity(self):
|
||||
def getSeverity(self) -> int:
|
||||
from panda3d.core import NSDebug, NSInfo, NSWarning, NSError
|
||||
if self.getDebug():
|
||||
return NSDebug
|
||||
|
|
@ -120,7 +125,7 @@ class Notifier:
|
|||
return NSError
|
||||
|
||||
# error funcs
|
||||
def error(self, errorString, exception=NotifierException):
|
||||
def error(self, errorString: object, exception: type[Exception] = NotifierException) -> NoReturn:
|
||||
"""
|
||||
Raise an exception with given string and optional type:
|
||||
Exception: error
|
||||
|
|
@ -134,7 +139,7 @@ class Notifier:
|
|||
raise exception(errorString)
|
||||
|
||||
# warning funcs
|
||||
def warning(self, warningString):
|
||||
def warning(self, warningString: object) -> int:
|
||||
"""
|
||||
Issue the warning message if warn flag is on
|
||||
"""
|
||||
|
|
@ -148,20 +153,20 @@ class Notifier:
|
|||
self.__print(string)
|
||||
return 1 # to allow assert myNotify.warning("blah")
|
||||
|
||||
def setWarning(self, enable):
|
||||
def setWarning(self, enable: bool) -> None:
|
||||
"""
|
||||
Enable/Disable the printing of warning messages
|
||||
"""
|
||||
self.__warning = enable
|
||||
|
||||
def getWarning(self):
|
||||
def getWarning(self) -> bool:
|
||||
"""
|
||||
Return whether the printing of warning messages is on or off
|
||||
"""
|
||||
return self.__warning
|
||||
|
||||
# debug funcs
|
||||
def debug(self, debugString):
|
||||
def debug(self, debugString: object) -> int:
|
||||
"""
|
||||
Issue the debug message if debug flag is on
|
||||
"""
|
||||
|
|
@ -175,20 +180,20 @@ class Notifier:
|
|||
self.__print(string)
|
||||
return 1 # to allow assert myNotify.debug("blah")
|
||||
|
||||
def setDebug(self, enable):
|
||||
def setDebug(self, enable: bool) -> None:
|
||||
"""
|
||||
Enable/Disable the printing of debug messages
|
||||
"""
|
||||
self.__debug = enable
|
||||
|
||||
def getDebug(self):
|
||||
def getDebug(self) -> bool:
|
||||
"""
|
||||
Return whether the printing of debug messages is on or off
|
||||
"""
|
||||
return self.__debug
|
||||
|
||||
# info funcs
|
||||
def info(self, infoString):
|
||||
def info(self, infoString: object) -> int:
|
||||
"""
|
||||
Print the given informational string, if info flag is on
|
||||
"""
|
||||
|
|
@ -202,39 +207,39 @@ class Notifier:
|
|||
self.__print(string)
|
||||
return 1 # to allow assert myNotify.info("blah")
|
||||
|
||||
def getInfo(self):
|
||||
def getInfo(self) -> bool:
|
||||
"""
|
||||
Return whether the printing of info messages is on or off
|
||||
"""
|
||||
return self.__info
|
||||
|
||||
def setInfo(self, enable):
|
||||
def setInfo(self, enable: bool) -> None:
|
||||
"""
|
||||
Enable/Disable informational message printing
|
||||
"""
|
||||
self.__info = enable
|
||||
|
||||
# log funcs
|
||||
def __log(self, logEntry):
|
||||
def __log(self, logEntry: str) -> None:
|
||||
"""
|
||||
Determine whether to send informational message to the logger
|
||||
"""
|
||||
if self.__logging:
|
||||
self.__logger.log(logEntry)
|
||||
|
||||
def getLogging(self):
|
||||
def getLogging(self) -> bool:
|
||||
"""
|
||||
Return 1 if logging enabled, 0 otherwise
|
||||
"""
|
||||
return self.__logging
|
||||
|
||||
def setLogging(self, enable):
|
||||
def setLogging(self, enable: bool) -> None:
|
||||
"""
|
||||
Set the logging flag to int (1=on, 0=off)
|
||||
"""
|
||||
self.__logging = enable
|
||||
|
||||
def __print(self, string):
|
||||
def __print(self, string: str) -> None:
|
||||
"""
|
||||
Prints the string to output followed by a newline.
|
||||
"""
|
||||
|
|
@ -251,7 +256,7 @@ class Notifier:
|
|||
the function call (with parameters).
|
||||
"""
|
||||
#f.f_locals['self'].__init__.im_class.__name__
|
||||
if self.__debug:
|
||||
if __debug__ and self.__debug:
|
||||
state = ''
|
||||
doId = ''
|
||||
if obj is not None:
|
||||
|
|
@ -285,13 +290,13 @@ class Notifier:
|
|||
self.__print(string)
|
||||
return 1 # to allow assert self.notify.debugStateCall(self)
|
||||
|
||||
def debugCall(self, debugString=''):
|
||||
def debugCall(self, debugString: object = '') -> int:
|
||||
"""
|
||||
If this notify is in debug mode, print the time of the
|
||||
call followed by the notifier category and
|
||||
the function call (with parameters).
|
||||
"""
|
||||
if self.__debug:
|
||||
if __debug__ and self.__debug:
|
||||
message = str(debugString)
|
||||
string = ":%s:%s \"%s\" %s"%(
|
||||
self.getOnlyTime(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import time
|
||||
from typing import Iterable
|
||||
|
||||
|
||||
class RotatingLog:
|
||||
|
|
@ -8,7 +11,12 @@ class RotatingLog:
|
|||
to a new file if the prior file is too large or after a time interval.
|
||||
"""
|
||||
|
||||
def __init__(self, path="./log_file", hourInterval=24, megabyteLimit=1024):
|
||||
def __init__(
|
||||
self,
|
||||
path: str = "./log_file",
|
||||
hourInterval: int | None = 24,
|
||||
megabyteLimit: int | None = 1024,
|
||||
) -> None:
|
||||
"""
|
||||
Args:
|
||||
path: a full or partial path with file name.
|
||||
|
|
@ -28,33 +36,33 @@ class RotatingLog:
|
|||
if megabyteLimit is not None:
|
||||
self.sizeLimit = megabyteLimit*1024*1024
|
||||
|
||||
def __del__(self):
|
||||
def __del__(self) -> None:
|
||||
self.close()
|
||||
|
||||
def close(self):
|
||||
def close(self) -> None:
|
||||
if hasattr(self, "file"):
|
||||
self.file.flush()
|
||||
self.file.close()
|
||||
self.closed = self.file.closed
|
||||
del self.file
|
||||
else:
|
||||
self.closed = 1
|
||||
self.closed = True
|
||||
|
||||
def shouldRotate(self):
|
||||
def shouldRotate(self) -> bool:
|
||||
"""
|
||||
Returns a bool about whether a new log file should
|
||||
be created and written to (while at the same time
|
||||
stopping output to the old log file and closing it).
|
||||
"""
|
||||
if not hasattr(self, "file"):
|
||||
return 1
|
||||
return True
|
||||
if self.timeLimit is not None and time.time() > self.timeLimit:
|
||||
return 1
|
||||
return True
|
||||
if self.sizeLimit is not None and self.file.tell() > self.sizeLimit:
|
||||
return 1
|
||||
return 0
|
||||
return True
|
||||
return False
|
||||
|
||||
def filePath(self):
|
||||
def filePath(self) -> str:
|
||||
dateString = time.strftime("%Y_%m_%d_%H", time.localtime())
|
||||
for i in range(26):
|
||||
limit = self.sizeLimit
|
||||
|
|
@ -65,7 +73,7 @@ class RotatingLog:
|
|||
# Maybe we should clear the self.sizeLimit here... maybe.
|
||||
return path
|
||||
|
||||
def rotate(self):
|
||||
def rotate(self) -> None:
|
||||
"""
|
||||
Rotate the log now. You normally shouldn't need to call this.
|
||||
See write().
|
||||
|
|
@ -88,12 +96,13 @@ class RotatingLog:
|
|||
#self.newlines = self.file.newlines # Python 2.3, maybe
|
||||
|
||||
if self.timeLimit is not None and time.time() > self.timeLimit:
|
||||
assert self.timeInterval is not None
|
||||
self.timeLimit=time.time()+self.timeInterval
|
||||
else:
|
||||
# We'll keep writing to the old file, if available.
|
||||
print("RotatingLog error: Unable to open new log file \"%s\"." % (path,))
|
||||
|
||||
def write(self, data):
|
||||
def write(self, data: str) -> int | None:
|
||||
"""
|
||||
Write the data to either the current log or a new one,
|
||||
depending on the return of shouldRotate() and whether
|
||||
|
|
@ -105,14 +114,15 @@ class RotatingLog:
|
|||
r = self.file.write(data)
|
||||
self.file.flush()
|
||||
return r
|
||||
return None
|
||||
|
||||
def flush(self):
|
||||
def flush(self) -> None:
|
||||
return self.file.flush()
|
||||
|
||||
def fileno(self):
|
||||
def fileno(self) -> int:
|
||||
return self.file.fileno()
|
||||
|
||||
def isatty(self):
|
||||
def isatty(self) -> bool:
|
||||
return self.file.isatty()
|
||||
|
||||
def __next__(self):
|
||||
|
|
@ -131,14 +141,14 @@ class RotatingLog:
|
|||
def xreadlines(self):
|
||||
return self.file.xreadlines()
|
||||
|
||||
def seek(self, offset, whence=0):
|
||||
def seek(self, offset: int, whence: int = 0) -> int:
|
||||
return self.file.seek(offset, whence)
|
||||
|
||||
def tell(self):
|
||||
def tell(self) -> int:
|
||||
return self.file.tell()
|
||||
|
||||
def truncate(self, size):
|
||||
def truncate(self, size: int | None) -> int:
|
||||
return self.file.truncate(size)
|
||||
|
||||
def writelines(self, sequence):
|
||||
def writelines(self, sequence: Iterable[str]) -> None:
|
||||
return self.file.writelines(sequence)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import math
|
||||
from panda3d.core import BitMask32, Mat4, NodePath, Point3, VBase3, Vec3, Vec4, rad2Deg
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
from .DirectUtil import CLAMP, useDirectRenderStyle
|
||||
from .DirectGeometry import getCrankAngle, getScreenXY
|
||||
from . import DirectGlobals as DG
|
||||
|
|
@ -26,7 +27,7 @@ class DirectCameraControl(DirectObject):
|
|||
self.orthoViewRoll = 0.0
|
||||
self.lastView = 0
|
||||
self.coa = Point3(0, 100, 0)
|
||||
self.coaMarker = base.loader.loadModel('models/misc/sphere')
|
||||
self.coaMarker = ShowBaseGlobal.loader.loadModel('models/misc/sphere')
|
||||
self.coaMarker.setName('DirectCameraCOAMarker')
|
||||
self.coaMarker.setTransparency(1)
|
||||
self.coaMarker.setColor(1, 0, 0, 0)
|
||||
|
|
@ -37,8 +38,8 @@ class DirectCameraControl(DirectObject):
|
|||
self.fLockCOA = 0
|
||||
self.nullHitPointCount = 0
|
||||
self.cqEntries = []
|
||||
self.coaMarkerRef = base.direct.group.attachNewNode('coaMarkerRef')
|
||||
self.camManipRef = base.direct.group.attachNewNode('camManipRef')
|
||||
self.coaMarkerRef = ShowBaseGlobal.direct.group.attachNewNode('coaMarkerRef')
|
||||
self.camManipRef = ShowBaseGlobal.direct.group.attachNewNode('camManipRef')
|
||||
self.switchDirBelowZero = True
|
||||
self.manipulateCameraTask = None
|
||||
self.manipulateCameraInterval = None
|
||||
|
|
@ -112,11 +113,6 @@ class DirectCameraControl(DirectObject):
|
|||
self.perspCollPlane2 = None # [gjeon] used for new LE
|
||||
|
||||
def toggleMarkerVis(self):
|
||||
## if base.direct.cameraControl.coaMarker.isHidden():
|
||||
## base.direct.cameraControl.coaMarker.show()
|
||||
## else:
|
||||
## base.direct.cameraControl.coaMarker.hide()
|
||||
|
||||
if self.coaMarker.isHidden():
|
||||
self.coaMarker.show()
|
||||
else:
|
||||
|
|
@ -132,11 +128,14 @@ class DirectCameraControl(DirectObject):
|
|||
# Hide the marker for this kind of motion
|
||||
self.coaMarker.hide()
|
||||
# Record time of start of mouse interaction
|
||||
base = ShowBaseGlobal.base
|
||||
self.startT = base.clock.getFrameTime()
|
||||
self.startF = base.clock.getFrameCount()
|
||||
# If the cam is orthogonal, spawn differentTask
|
||||
if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView and\
|
||||
base.direct.camera.getName() != 'persp':
|
||||
direct = ShowBaseGlobal.direct
|
||||
if hasattr(direct, "manipulationControl") and \
|
||||
direct.manipulationControl.fMultiView and \
|
||||
direct.camera.getName() != 'persp':
|
||||
self.spawnOrthoZoom()
|
||||
else:
|
||||
# Start manipulation
|
||||
|
|
@ -167,7 +166,9 @@ class DirectCameraControl(DirectObject):
|
|||
|
||||
def mouseFlyStart(self, modifiers):
|
||||
# Record undo point
|
||||
# base.direct.pushUndo([base.direct.camera]) # Wasteful use of undo
|
||||
base = ShowBaseGlobal.base
|
||||
direct = ShowBaseGlobal.direct
|
||||
#direct.pushUndo([direct.camera]) # Wasteful use of undo
|
||||
if self.useMayaCamControls and modifiers == 4: # alt is down, use maya controls
|
||||
# Hide the marker for this kind of motion
|
||||
self.coaMarker.hide()
|
||||
|
|
@ -176,15 +177,16 @@ class DirectCameraControl(DirectObject):
|
|||
self.startF = base.clock.getFrameCount()
|
||||
# Start manipulation
|
||||
# If the cam is orthogonal, spawn differentTask
|
||||
if hasattr(base.direct, "manipulationControl") and base.direct.manipulationControl.fMultiView and\
|
||||
base.direct.camera.getName() != 'persp':
|
||||
if hasattr(direct, "manipulationControl") and \
|
||||
direct.manipulationControl.fMultiView and \
|
||||
direct.camera.getName() != 'persp':
|
||||
self.spawnOrthoTranslate()
|
||||
else:
|
||||
self.spawnXZTranslate()
|
||||
self.altDown = 1
|
||||
elif not self.useMayaCamControls:
|
||||
# Where are we in the display region?
|
||||
if ((abs(base.direct.dr.mouseX) < 0.9) and (abs(base.direct.dr.mouseY) < 0.9)):
|
||||
if abs(direct.dr.mouseX) < 0.9 and abs(direct.dr.mouseY) < 0.9:
|
||||
# MOUSE IS IN CENTRAL REGION
|
||||
# Hide the marker for this kind of motion
|
||||
self.coaMarker.hide()
|
||||
|
|
@ -194,19 +196,18 @@ class DirectCameraControl(DirectObject):
|
|||
# Start manipulation
|
||||
self.spawnXZTranslateOrHPanYZoom()
|
||||
# END MOUSE IN CENTRAL REGION
|
||||
elif abs(direct.dr.mouseX) > 0.9 and abs(direct.dr.mouseY) > 0.9:
|
||||
# Mouse is in corners, spawn roll task
|
||||
self.spawnMouseRollTask()
|
||||
else:
|
||||
if ((abs(base.direct.dr.mouseX) > 0.9) and
|
||||
(abs(base.direct.dr.mouseY) > 0.9)):
|
||||
# Mouse is in corners, spawn roll task
|
||||
self.spawnMouseRollTask()
|
||||
else:
|
||||
# Mouse is in outer frame, spawn mouseRotateTask
|
||||
self.spawnMouseRotateTask()
|
||||
# Mouse is in outer frame, spawn mouseRotateTask
|
||||
self.spawnMouseRotateTask()
|
||||
if not modifiers == 4:
|
||||
self.altDown = 0
|
||||
|
||||
def mouseFlyStop(self):
|
||||
self.__stopManipulateCamera()
|
||||
base = ShowBaseGlobal.base
|
||||
stopT = base.clock.getFrameTime()
|
||||
deltaT = stopT - self.startT
|
||||
stopF = base.clock.getFrameCount()
|
||||
|
|
@ -215,7 +216,8 @@ class DirectCameraControl(DirectObject):
|
|||
# if not self.useMayaCamControls and (deltaT <= 0.25) or (deltaF <= 1):
|
||||
|
||||
# Do this when not trying to manipulate camera
|
||||
if not self.altDown and len(base.direct.selected.getSelectedAsList()) == 0:
|
||||
direct = ShowBaseGlobal.direct
|
||||
if not self.altDown and len(direct.selected.getSelectedAsList()) == 0:
|
||||
# Check for a hit point based on
|
||||
# current mouse position
|
||||
# Allow intersection with unpickable objects
|
||||
|
|
@ -224,13 +226,13 @@ class DirectCameraControl(DirectObject):
|
|||
skipFlags = DG.SKIP_HIDDEN | DG.SKIP_BACKFACE
|
||||
# Skip camera (and its children), unless control key is pressed
|
||||
skipFlags |= DG.SKIP_CAMERA * (1 - base.getControl())
|
||||
self.computeCOA(base.direct.iRay.pickGeom(skipFlags = skipFlags))
|
||||
self.computeCOA(direct.iRay.pickGeom(skipFlags = skipFlags))
|
||||
# Record reference point
|
||||
self.coaMarkerRef.setPosHprScale(base.cam, 0, 0, 0, 0, 0, 0, 1, 1, 1)
|
||||
# Record entries
|
||||
self.cqEntries = []
|
||||
for i in range(base.direct.iRay.getNumEntries()):
|
||||
self.cqEntries.append(base.direct.iRay.getEntry(i))
|
||||
for i in range(direct.iRay.getNumEntries()):
|
||||
self.cqEntries.append(direct.iRay.getEntry(i))
|
||||
# Show the marker
|
||||
self.coaMarker.show()
|
||||
# Resize it
|
||||
|
|
@ -251,7 +253,7 @@ class DirectCameraControl(DirectObject):
|
|||
# Spawn the new task
|
||||
t = Task.Task(self.XZTranslateOrHPanYZoomTask)
|
||||
# For HPanYZoom
|
||||
t.zoomSF = Vec3(self.coaMarker.getPos(base.direct.camera)).length()
|
||||
t.zoomSF = Vec3(self.coaMarker.getPos(ShowBaseGlobal.direct.camera)).length()
|
||||
self.__startManipulateCamera(task = t)
|
||||
|
||||
def spawnXZTranslateOrHPPan(self):
|
||||
|
|
@ -277,7 +279,7 @@ class DirectCameraControl(DirectObject):
|
|||
self.__stopManipulateCamera()
|
||||
# Spawn new task
|
||||
t = Task.Task(self.HPanYZoomTask)
|
||||
t.zoomSF = Vec3(self.coaMarker.getPos(base.direct.camera)).length()
|
||||
t.zoomSF = Vec3(self.coaMarker.getPos(ShowBaseGlobal.direct.camera)).length()
|
||||
self.__startManipulateCamera(task = t)
|
||||
|
||||
def spawnOrthoZoom(self):
|
||||
|
|
@ -294,13 +296,13 @@ class DirectCameraControl(DirectObject):
|
|||
self.__startManipulateCamera(func = self.HPPanTask)
|
||||
|
||||
def XZTranslateOrHPanYZoomTask(self, state):
|
||||
if base.direct.fShift:
|
||||
if ShowBaseGlobal.direct.fShift:
|
||||
return self.XZTranslateTask(state)
|
||||
else:
|
||||
return self.HPanYZoomTask(state)
|
||||
|
||||
def XZTranslateOrHPPanTask(self, state):
|
||||
if base.direct.fShift:
|
||||
if ShowBaseGlobal.direct.fShift:
|
||||
# Panning action
|
||||
return self.HPPanTask(state)
|
||||
else:
|
||||
|
|
@ -308,43 +310,46 @@ class DirectCameraControl(DirectObject):
|
|||
return self.XZTranslateTask(state)
|
||||
|
||||
def XZTranslateTask(self, state):
|
||||
coaDist = Vec3(self.coaMarker.getPos(base.direct.camera)).length()
|
||||
xlateSF = coaDist / base.direct.dr.near
|
||||
base.direct.camera.setPos(base.direct.camera,
|
||||
(-0.5 * base.direct.dr.mouseDeltaX *
|
||||
base.direct.dr.nearWidth *
|
||||
direct = ShowBaseGlobal.direct
|
||||
coaDist = Vec3(self.coaMarker.getPos(direct.camera)).length()
|
||||
xlateSF = coaDist / direct.dr.near
|
||||
direct.camera.setPos(direct.camera,
|
||||
(-0.5 * direct.dr.mouseDeltaX *
|
||||
direct.dr.nearWidth *
|
||||
xlateSF),
|
||||
0.0,
|
||||
(-0.5 * base.direct.dr.mouseDeltaY *
|
||||
base.direct.dr.nearHeight *
|
||||
(-0.5 * direct.dr.mouseDeltaY *
|
||||
direct.dr.nearHeight *
|
||||
xlateSF))
|
||||
return Task.cont
|
||||
|
||||
def OrthoTranslateTask(self, state):
|
||||
# create ray from the camera to detect 3d position
|
||||
iRay = SelectionRay(base.direct.camera)
|
||||
iRay.collider.setFromLens(base.direct.camNode, base.direct.dr.mouseX, base.direct.dr.mouseY)
|
||||
direct = ShowBaseGlobal.direct
|
||||
iRay = SelectionRay(direct.camera)
|
||||
iRay.collider.setFromLens(direct.camNode, direct.dr.mouseX, direct.dr.mouseY)
|
||||
#iRay.collideWithBitMask(1)
|
||||
iRay.collideWithBitMask(BitMask32.bit(21))
|
||||
iRay.ct.traverse(base.direct.grid)
|
||||
iRay.ct.traverse(direct.grid)
|
||||
|
||||
entry = iRay.getEntry(0)
|
||||
hitPt = entry.getSurfacePoint(entry.getFromNodePath())
|
||||
iRay.collisionNodePath.removeNode()
|
||||
del iRay
|
||||
if hasattr(state, 'prevPt'):
|
||||
base.direct.camera.setPos(base.direct.camera, (state.prevPt - hitPt))
|
||||
direct.camera.setPos(direct.camera, (state.prevPt - hitPt))
|
||||
state.prevPt = hitPt
|
||||
return Task.cont
|
||||
|
||||
def HPanYZoomTask(self, state):
|
||||
# If the cam is orthogonal, don't rotate or zoom.
|
||||
if (hasattr(base.direct.cam.node(), "getLens") and
|
||||
base.direct.cam.node().getLens().__class__.__name__ == "OrthographicLens"):
|
||||
direct = ShowBaseGlobal.direct
|
||||
if (hasattr(direct.cam.node(), "getLens") and
|
||||
direct.cam.node().getLens().__class__.__name__ == "OrthographicLens"):
|
||||
return
|
||||
|
||||
if base.direct.fControl:
|
||||
moveDir = Vec3(self.coaMarker.getPos(base.direct.camera))
|
||||
if direct.fControl:
|
||||
moveDir = Vec3(self.coaMarker.getPos(direct.camera))
|
||||
# If marker is behind camera invert vector
|
||||
if moveDir[1] < 0.0:
|
||||
moveDir.assign(moveDir * -1)
|
||||
|
|
@ -353,18 +358,18 @@ class DirectCameraControl(DirectObject):
|
|||
moveDir = Vec3(Y_AXIS)
|
||||
|
||||
if self.useMayaCamControls: # use maya controls
|
||||
moveDir.assign(moveDir * ((base.direct.dr.mouseDeltaX -1.0 * base.direct.dr.mouseDeltaY)
|
||||
moveDir.assign(moveDir * ((direct.dr.mouseDeltaX -1.0 * direct.dr.mouseDeltaY)
|
||||
* state.zoomSF))
|
||||
hVal = 0.0
|
||||
else:
|
||||
moveDir.assign(moveDir * (-1.0 * base.direct.dr.mouseDeltaY *
|
||||
moveDir.assign(moveDir * (-1.0 * direct.dr.mouseDeltaY *
|
||||
state.zoomSF))
|
||||
if base.direct.dr.mouseDeltaY > 0.0:
|
||||
if direct.dr.mouseDeltaY > 0.0:
|
||||
moveDir.setY(moveDir[1] * 1.0)
|
||||
|
||||
hVal = 0.5 * base.direct.dr.mouseDeltaX * base.direct.dr.fovH
|
||||
hVal = 0.5 * direct.dr.mouseDeltaX * direct.dr.fovH
|
||||
|
||||
base.direct.camera.setPosHpr(base.direct.camera,
|
||||
direct.camera.setPosHpr(direct.camera,
|
||||
moveDir[0],
|
||||
moveDir[1],
|
||||
moveDir[2],
|
||||
|
|
@ -372,39 +377,42 @@ class DirectCameraControl(DirectObject):
|
|||
0.0, 0.0)
|
||||
if self.lockRoll:
|
||||
# flatten roll
|
||||
base.direct.camera.setR(0)
|
||||
direct.camera.setR(0)
|
||||
|
||||
return Task.cont
|
||||
|
||||
def OrthoZoomTask(self, state):
|
||||
filmSize = base.direct.camNode.getLens().getFilmSize()
|
||||
factor = (base.direct.dr.mouseDeltaX -1.0 * base.direct.dr.mouseDeltaY) * 0.1
|
||||
x = base.direct.dr.getWidth()
|
||||
y = base.direct.dr.getHeight()
|
||||
base.direct.dr.orthoFactor -= factor
|
||||
if base.direct.dr.orthoFactor < 0:
|
||||
base.direct.dr.orthoFactor = 0.0001
|
||||
base.direct.dr.updateFilmSize(x, y)
|
||||
direct = ShowBaseGlobal.direct
|
||||
filmSize = direct.camNode.getLens().getFilmSize()
|
||||
factor = (direct.dr.mouseDeltaX -1.0 * direct.dr.mouseDeltaY) * 0.1
|
||||
x = direct.dr.getWidth()
|
||||
y = direct.dr.getHeight()
|
||||
direct.dr.orthoFactor -= factor
|
||||
if direct.dr.orthoFactor < 0:
|
||||
direct.dr.orthoFactor = 0.0001
|
||||
direct.dr.updateFilmSize(x, y)
|
||||
return Task.cont
|
||||
|
||||
def HPPanTask(self, state):
|
||||
base.direct.camera.setHpr(base.direct.camera,
|
||||
(0.5 * base.direct.dr.mouseDeltaX *
|
||||
base.direct.dr.fovH),
|
||||
(-0.5 * base.direct.dr.mouseDeltaY *
|
||||
base.direct.dr.fovV),
|
||||
direct = ShowBaseGlobal.direct
|
||||
direct.camera.setHpr(direct.camera,
|
||||
(0.5 * direct.dr.mouseDeltaX *
|
||||
direct.dr.fovH),
|
||||
(-0.5 * direct.dr.mouseDeltaY *
|
||||
direct.dr.fovV),
|
||||
0.0)
|
||||
return Task.cont
|
||||
|
||||
def spawnMouseRotateTask(self):
|
||||
# Kill any existing tasks
|
||||
self.__stopManipulateCamera()
|
||||
direct = ShowBaseGlobal.direct
|
||||
if self.perspCollPlane:
|
||||
iRay = SelectionRay(base.direct.camera)
|
||||
iRay.collider.setFromLens(base.direct.camNode, 0.0, 0.0)
|
||||
iRay = SelectionRay(direct.camera)
|
||||
iRay.collider.setFromLens(direct.camNode, 0.0, 0.0)
|
||||
iRay.collideWithBitMask(1)
|
||||
|
||||
if base.direct.camera.getPos().getZ() >=0:
|
||||
if direct.camera.getPos().getZ() >=0:
|
||||
iRay.ct.traverse(self.perspCollPlane)
|
||||
else:
|
||||
iRay.ct.traverse(self.perspCollPlane2)
|
||||
|
|
@ -415,7 +423,7 @@ class DirectCameraControl(DirectObject):
|
|||
|
||||
# create a temp nodePath to get the position
|
||||
np = NodePath('temp')
|
||||
np.setPos(base.direct.camera, hitPt)
|
||||
np.setPos(direct.camera, hitPt)
|
||||
self.coaMarkerPos = np.getPos()
|
||||
np.removeNode()
|
||||
self.coaMarker.setPos(self.coaMarkerPos)
|
||||
|
|
@ -425,9 +433,9 @@ class DirectCameraControl(DirectObject):
|
|||
|
||||
# Set at markers position in render coordinates
|
||||
self.camManipRef.setPos(self.coaMarkerPos)
|
||||
self.camManipRef.setHpr(base.direct.camera, DG.ZERO_POINT)
|
||||
self.camManipRef.setHpr(direct.camera, DG.ZERO_POINT)
|
||||
t = Task.Task(self.mouseRotateTask)
|
||||
if abs(base.direct.dr.mouseX) > 0.9:
|
||||
if abs(direct.dr.mouseX) > 0.9:
|
||||
t.constrainedDir = 'y'
|
||||
else:
|
||||
t.constrainedDir = 'x'
|
||||
|
|
@ -435,36 +443,37 @@ class DirectCameraControl(DirectObject):
|
|||
|
||||
def mouseRotateTask(self, state):
|
||||
# If the cam is orthogonal, don't rotate.
|
||||
if (hasattr(base.direct.cam.node(), "getLens") and
|
||||
base.direct.cam.node().getLens().__class__.__name__ == "OrthographicLens"):
|
||||
direct = ShowBaseGlobal.direct
|
||||
if (hasattr(direct.cam.node(), "getLens") and
|
||||
direct.cam.node().getLens().__class__.__name__ == "OrthographicLens"):
|
||||
return
|
||||
# If moving outside of center, ignore motion perpendicular to edge
|
||||
if ((state.constrainedDir == 'y') and (abs(base.direct.dr.mouseX) > 0.9)):
|
||||
if ((state.constrainedDir == 'y') and (abs(direct.dr.mouseX) > 0.9)):
|
||||
deltaX = 0
|
||||
deltaY = base.direct.dr.mouseDeltaY
|
||||
elif ((state.constrainedDir == 'x') and (abs(base.direct.dr.mouseY) > 0.9)):
|
||||
deltaX = base.direct.dr.mouseDeltaX
|
||||
deltaY = direct.dr.mouseDeltaY
|
||||
elif ((state.constrainedDir == 'x') and (abs(direct.dr.mouseY) > 0.9)):
|
||||
deltaX = direct.dr.mouseDeltaX
|
||||
deltaY = 0
|
||||
else:
|
||||
deltaX = base.direct.dr.mouseDeltaX
|
||||
deltaY = base.direct.dr.mouseDeltaY
|
||||
if base.direct.fShift:
|
||||
base.direct.camera.setHpr(base.direct.camera,
|
||||
(deltaX * base.direct.dr.fovH),
|
||||
(-deltaY * base.direct.dr.fovV),
|
||||
deltaX = direct.dr.mouseDeltaX
|
||||
deltaY = direct.dr.mouseDeltaY
|
||||
if direct.fShift:
|
||||
direct.camera.setHpr(direct.camera,
|
||||
(deltaX * direct.dr.fovH),
|
||||
(-deltaY * direct.dr.fovV),
|
||||
0.0)
|
||||
if self.lockRoll:
|
||||
# flatten roll
|
||||
base.direct.camera.setR(0)
|
||||
direct.camera.setR(0)
|
||||
self.camManipRef.setPos(self.coaMarkerPos)
|
||||
self.camManipRef.setHpr(base.direct.camera, DG.ZERO_POINT)
|
||||
self.camManipRef.setHpr(direct.camera, DG.ZERO_POINT)
|
||||
else:
|
||||
if base.direct.camera.getPos().getZ() >=0 or not self.switchDirBelowZero:
|
||||
if direct.camera.getPos().getZ() >=0 or not self.switchDirBelowZero:
|
||||
dirX = -1
|
||||
else:
|
||||
dirX = 1
|
||||
|
||||
wrt = base.direct.camera.getTransform(self.camManipRef)
|
||||
wrt = direct.camera.getTransform(self.camManipRef)
|
||||
self.camManipRef.setHpr(self.camManipRef,
|
||||
(dirX * deltaX * 180.0),
|
||||
(deltaY * 180.0),
|
||||
|
|
@ -473,20 +482,21 @@ class DirectCameraControl(DirectObject):
|
|||
if self.lockRoll:
|
||||
# flatten roll
|
||||
self.camManipRef.setR(0)
|
||||
base.direct.camera.setTransform(self.camManipRef, wrt)
|
||||
direct.camera.setTransform(self.camManipRef, wrt)
|
||||
return Task.cont
|
||||
|
||||
def spawnMouseRollTask(self):
|
||||
# Kill any existing tasks
|
||||
self.__stopManipulateCamera()
|
||||
# Set at markers position in render coordinates
|
||||
direct = ShowBaseGlobal.direct
|
||||
self.camManipRef.setPos(self.coaMarkerPos)
|
||||
self.camManipRef.setHpr(base.direct.camera, DG.ZERO_POINT)
|
||||
self.camManipRef.setHpr(direct.camera, DG.ZERO_POINT)
|
||||
t = Task.Task(self.mouseRollTask)
|
||||
t.coaCenter = getScreenXY(self.coaMarker)
|
||||
t.lastAngle = getCrankAngle(t.coaCenter)
|
||||
# Store the camera/manipRef offset transform
|
||||
t.wrt = base.direct.camera.getTransform(self.camManipRef)
|
||||
t.wrt = direct.camera.getTransform(self.camManipRef)
|
||||
self.__startManipulateCamera(task = t)
|
||||
|
||||
def mouseRollTask(self, state):
|
||||
|
|
@ -498,23 +508,23 @@ class DirectCameraControl(DirectObject):
|
|||
if self.lockRoll:
|
||||
# flatten roll
|
||||
self.camManipRef.setR(0)
|
||||
base.direct.camera.setTransform(self.camManipRef, wrt)
|
||||
ShowBaseGlobal.direct.camera.setTransform(self.camManipRef, wrt)
|
||||
return Task.cont
|
||||
|
||||
def lockCOA(self):
|
||||
self.fLockCOA = 1
|
||||
base.direct.message('COA Lock On')
|
||||
ShowBaseGlobal.direct.message('COA Lock On')
|
||||
|
||||
def unlockCOA(self):
|
||||
self.fLockCOA = 0
|
||||
base.direct.message('COA Lock Off')
|
||||
ShowBaseGlobal.direct.message('COA Lock Off')
|
||||
|
||||
def toggleCOALock(self):
|
||||
self.fLockCOA = 1 - self.fLockCOA
|
||||
if self.fLockCOA:
|
||||
base.direct.message('COA Lock On')
|
||||
ShowBaseGlobal.direct.message('COA Lock On')
|
||||
else:
|
||||
base.direct.message('COA Lock Off')
|
||||
ShowBaseGlobal.direct.message('COA Lock Off')
|
||||
|
||||
def pickNextCOA(self):
|
||||
""" Cycle through collision handler entries """
|
||||
|
|
@ -524,7 +534,7 @@ class DirectCameraControl(DirectObject):
|
|||
self.cqEntries = self.cqEntries[1:] + self.cqEntries[:1]
|
||||
# Filter out object's under camera
|
||||
nodePath = entry.getIntoNodePath()
|
||||
if base.direct.camera not in nodePath.getAncestors():
|
||||
if ShowBaseGlobal.direct.camera not in nodePath.getAncestors():
|
||||
# Compute new hit point
|
||||
hitPt = entry.getSurfacePoint(entry.getFromNodePath())
|
||||
# Move coa marker to new point
|
||||
|
|
@ -536,11 +546,11 @@ class DirectCameraControl(DirectObject):
|
|||
|
||||
def computeCOA(self, entry):
|
||||
coa = Point3(0)
|
||||
dr = base.direct.drList.getCurrentDr()
|
||||
dr = ShowBaseGlobal.direct.drList.getCurrentDr()
|
||||
if self.fLockCOA:
|
||||
# COA is locked, use existing point
|
||||
# Use existing point
|
||||
coa.assign(self.coaMarker.getPos(base.direct.camera))
|
||||
coa.assign(self.coaMarker.getPos(ShowBaseGlobal.direct.camera))
|
||||
# Reset hit point count
|
||||
self.nullHitPointCount = 0
|
||||
elif entry:
|
||||
|
|
@ -553,7 +563,7 @@ class DirectCameraControl(DirectObject):
|
|||
if ((hitPtDist < (1.1 * dr.near)) or
|
||||
(hitPtDist > dr.far)):
|
||||
# Just use existing point
|
||||
coa.assign(self.coaMarker.getPos(base.direct.camera))
|
||||
coa.assign(self.coaMarker.getPos(ShowBaseGlobal.direct.camera))
|
||||
# Reset hit point count
|
||||
self.nullHitPointCount = 0
|
||||
else:
|
||||
|
|
@ -565,7 +575,7 @@ class DirectCameraControl(DirectObject):
|
|||
# MRM: Would be nice to be able to control this
|
||||
# At least display it
|
||||
dist = pow(10.0, self.nullHitPointCount)
|
||||
base.direct.message('COA Distance: ' + repr(dist))
|
||||
ShowBaseGlobal.direct.message('COA Distance: ' + repr(dist))
|
||||
coa.set(0, dist, 0)
|
||||
# Compute COA Dist
|
||||
coaDist = Vec3(coa - DG.ZERO_POINT).length()
|
||||
|
|
@ -583,7 +593,7 @@ class DirectCameraControl(DirectObject):
|
|||
if ref is None:
|
||||
# KEH: use the current display region
|
||||
# ref = base.cam
|
||||
ref = base.direct.drList.getCurrentDr().cam
|
||||
ref = ShowBaseGlobal.direct.drList.getCurrentDr().cam
|
||||
self.coaMarker.setPos(ref, self.coa)
|
||||
pos = self.coaMarker.getPos()
|
||||
self.coaMarker.setPosHprScale(pos, Vec3(0), Vec3(1))
|
||||
|
|
@ -598,10 +608,10 @@ class DirectCameraControl(DirectObject):
|
|||
|
||||
def updateCoaMarkerSize(self, coaDist = None):
|
||||
if not coaDist:
|
||||
coaDist = Vec3(self.coaMarker.getPos(base.direct.camera)).length()
|
||||
coaDist = Vec3(self.coaMarker.getPos(ShowBaseGlobal.direct.camera)).length()
|
||||
# Nominal size based on default 30 degree vertical FOV
|
||||
# Need to adjust size based on distance and current FOV
|
||||
sf = COA_MARKER_SF * coaDist * (base.direct.drList.getCurrentDr().fovV/30.0)
|
||||
sf = COA_MARKER_SF * coaDist * (ShowBaseGlobal.direct.drList.getCurrentDr().fovV/30.0)
|
||||
if sf == 0.0:
|
||||
sf = 0.1
|
||||
self.coaMarker.setScale(sf)
|
||||
|
|
@ -619,32 +629,36 @@ class DirectCameraControl(DirectObject):
|
|||
|
||||
def homeCam(self):
|
||||
# Record undo point
|
||||
base.direct.pushUndo([base.direct.camera])
|
||||
base.direct.camera.reparentTo(render)
|
||||
base.direct.camera.clearMat()
|
||||
direct = ShowBaseGlobal.direct
|
||||
direct.pushUndo([direct.camera])
|
||||
direct.camera.reparentTo(ShowBaseGlobal.base.render)
|
||||
direct.camera.clearMat()
|
||||
# Resize coa marker
|
||||
self.updateCoaMarkerSize()
|
||||
|
||||
def uprightCam(self):
|
||||
self.__stopManipulateCamera()
|
||||
# Record undo point
|
||||
base.direct.pushUndo([base.direct.camera])
|
||||
direct = ShowBaseGlobal.direct
|
||||
direct.pushUndo([direct.camera])
|
||||
# Pitch camera till upright
|
||||
currH = base.direct.camera.getH()
|
||||
ival = base.direct.camera.hprInterval(CAM_MOVE_DURATION,
|
||||
(currH, 0, 0),
|
||||
other = render,
|
||||
blendType = 'easeInOut',
|
||||
name = 'manipulateCamera')
|
||||
self.__startManipulateCamera(ival = ival)
|
||||
currH = direct.camera.getH()
|
||||
ival = direct.camera.hprInterval(CAM_MOVE_DURATION,
|
||||
(currH, 0, 0),
|
||||
other=ShowBaseGlobal.base.render,
|
||||
blendType='easeInOut',
|
||||
name='manipulateCamera')
|
||||
self.__startManipulateCamera(ival=ival)
|
||||
|
||||
def orbitUprightCam(self):
|
||||
self.__stopManipulateCamera()
|
||||
# Record undo point
|
||||
base.direct.pushUndo([base.direct.camera])
|
||||
direct = ShowBaseGlobal.direct
|
||||
direct.pushUndo([direct.camera])
|
||||
# Transform camera z axis to render space
|
||||
render = ShowBaseGlobal.base.render
|
||||
mCam2Render = Mat4(Mat4.identMat()) # [gjeon] fixed to give required argument
|
||||
mCam2Render.assign(base.direct.camera.getMat(render))
|
||||
mCam2Render.assign(direct.camera.getMat(render))
|
||||
zAxis = Vec3(mCam2Render.xformVec(DG.Z_AXIS))
|
||||
zAxis.normalize()
|
||||
# Compute rotation angle needed to upright cam
|
||||
|
|
@ -665,8 +679,8 @@ class DirectCameraControl(DirectObject):
|
|||
self.camManipRef.setPos(self.coaMarker, Vec3(0))
|
||||
self.camManipRef.setHpr(render, rotAngle, 0, 0)
|
||||
# Reparent Cam to ref Coordinate system
|
||||
parent = base.direct.camera.getParent()
|
||||
base.direct.camera.wrtReparentTo(self.camManipRef)
|
||||
parent = direct.camera.getParent()
|
||||
direct.camera.wrtReparentTo(self.camManipRef)
|
||||
# Rotate ref CS to final orientation
|
||||
ival = self.camManipRef.hprInterval(CAM_MOVE_DURATION,
|
||||
(rotAngle, orbitAngle, 0),
|
||||
|
|
@ -685,17 +699,18 @@ class DirectCameraControl(DirectObject):
|
|||
def centerCamIn(self, t):
|
||||
self.__stopManipulateCamera()
|
||||
# Record undo point
|
||||
base.direct.pushUndo([base.direct.camera])
|
||||
direct = ShowBaseGlobal.direct
|
||||
direct.pushUndo([direct.camera])
|
||||
# Determine marker location
|
||||
markerToCam = self.coaMarker.getPos(base.direct.camera)
|
||||
markerToCam = self.coaMarker.getPos(direct.camera)
|
||||
dist = Vec3(markerToCam - DG.ZERO_POINT).length()
|
||||
scaledCenterVec = Y_AXIS * dist
|
||||
delta = markerToCam - scaledCenterVec
|
||||
self.camManipRef.setPosHpr(base.direct.camera, Point3(0), Point3(0))
|
||||
ival = base.direct.camera.posInterval(CAM_MOVE_DURATION,
|
||||
Point3(delta),
|
||||
other = self.camManipRef,
|
||||
blendType = 'easeInOut')
|
||||
self.camManipRef.setPosHpr(direct.camera, Point3(0), Point3(0))
|
||||
ival = direct.camera.posInterval(CAM_MOVE_DURATION,
|
||||
Point3(delta),
|
||||
other=self.camManipRef,
|
||||
blendType='easeInOut')
|
||||
ival = Sequence(ival, Func(self.updateCoaMarkerSizeOnDeath),
|
||||
name = 'manipulateCamera')
|
||||
self.__startManipulateCamera(ival = ival)
|
||||
|
|
@ -703,17 +718,18 @@ class DirectCameraControl(DirectObject):
|
|||
def zoomCam(self, zoomFactor, t):
|
||||
self.__stopManipulateCamera()
|
||||
# Record undo point
|
||||
base.direct.pushUndo([base.direct.camera])
|
||||
direct = ShowBaseGlobal.direct
|
||||
direct.pushUndo([direct.camera])
|
||||
# Find a point zoom factor times the current separation
|
||||
# of the widget and cam
|
||||
zoomPtToCam = self.coaMarker.getPos(base.direct.camera) * zoomFactor
|
||||
zoomPtToCam = self.coaMarker.getPos(direct.camera) * zoomFactor
|
||||
# Put a target nodePath there
|
||||
self.camManipRef.setPos(base.direct.camera, zoomPtToCam)
|
||||
self.camManipRef.setPos(direct.camera, zoomPtToCam)
|
||||
# Move to that point
|
||||
ival = base.direct.camera.posInterval(CAM_MOVE_DURATION,
|
||||
DG.ZERO_POINT,
|
||||
other = self.camManipRef,
|
||||
blendType = 'easeInOut')
|
||||
ival = direct.camera.posInterval(CAM_MOVE_DURATION,
|
||||
DG.ZERO_POINT,
|
||||
other=self.camManipRef,
|
||||
blendType='easeInOut')
|
||||
ival = Sequence(ival, Func(self.updateCoaMarkerSizeOnDeath),
|
||||
name = 'manipulateCamera')
|
||||
self.__startManipulateCamera(ival = ival)
|
||||
|
|
@ -722,7 +738,8 @@ class DirectCameraControl(DirectObject):
|
|||
# Kill any existing tasks
|
||||
self.__stopManipulateCamera()
|
||||
# Record undo point
|
||||
base.direct.pushUndo([base.direct.camera])
|
||||
direct = ShowBaseGlobal.direct
|
||||
direct.pushUndo([direct.camera])
|
||||
# Calc hprOffset
|
||||
hprOffset = VBase3()
|
||||
if view == 8:
|
||||
|
|
@ -751,7 +768,7 @@ class DirectCameraControl(DirectObject):
|
|||
self.camManipRef.setPosHpr(self.coaMarker, DG.ZERO_VEC,
|
||||
hprOffset)
|
||||
# Scale center vec by current distance to target
|
||||
offsetDistance = Vec3(base.direct.camera.getPos(self.camManipRef) -
|
||||
offsetDistance = Vec3(direct.camera.getPos(self.camManipRef) -
|
||||
DG.ZERO_POINT).length()
|
||||
scaledCenterVec = Y_AXIS * (-1.0 * offsetDistance)
|
||||
# Now put the camManipRef at that point
|
||||
|
|
@ -760,11 +777,11 @@ class DirectCameraControl(DirectObject):
|
|||
DG.ZERO_VEC)
|
||||
# Record view for next time around
|
||||
self.lastView = view
|
||||
ival = base.direct.camera.posHprInterval(CAM_MOVE_DURATION,
|
||||
pos = DG.ZERO_POINT,
|
||||
hpr = VBase3(0, 0, self.orthoViewRoll),
|
||||
other = self.camManipRef,
|
||||
blendType = 'easeInOut')
|
||||
ival = direct.camera.posHprInterval(CAM_MOVE_DURATION,
|
||||
pos=DG.ZERO_POINT,
|
||||
hpr=VBase3(0, 0, self.orthoViewRoll),
|
||||
other=self.camManipRef,
|
||||
blendType='easeInOut')
|
||||
ival = Sequence(ival, Func(self.updateCoaMarkerSizeOnDeath),
|
||||
name = 'manipulateCamera')
|
||||
self.__startManipulateCamera(ival = ival)
|
||||
|
|
@ -774,15 +791,16 @@ class DirectCameraControl(DirectObject):
|
|||
self.__stopManipulateCamera()
|
||||
|
||||
# Record undo point
|
||||
base.direct.pushUndo([base.direct.camera])
|
||||
direct = ShowBaseGlobal.direct
|
||||
direct.pushUndo([direct.camera])
|
||||
|
||||
# Coincident with widget
|
||||
self.camManipRef.setPos(self.coaMarker, DG.ZERO_POINT)
|
||||
# But aligned with render space
|
||||
self.camManipRef.setHpr(DG.ZERO_POINT)
|
||||
|
||||
parent = base.direct.camera.getParent()
|
||||
base.direct.camera.wrtReparentTo(self.camManipRef)
|
||||
parent = direct.camera.getParent()
|
||||
direct.camera.wrtReparentTo(self.camManipRef)
|
||||
|
||||
ival = self.camManipRef.hprInterval(CAM_MOVE_DURATION,
|
||||
VBase3(degrees, 0, 0),
|
||||
|
|
@ -792,7 +810,7 @@ class DirectCameraControl(DirectObject):
|
|||
self.__startManipulateCamera(ival = ival)
|
||||
|
||||
def reparentCam(self, parent):
|
||||
base.direct.camera.wrtReparentTo(parent)
|
||||
ShowBaseGlobal.direct.camera.wrtReparentTo(parent)
|
||||
self.updateCoaMarkerSize()
|
||||
|
||||
def fitOnWidget(self, nodePath = 'None Given'):
|
||||
|
|
@ -800,75 +818,78 @@ class DirectCameraControl(DirectObject):
|
|||
# stop any ongoing tasks
|
||||
self.__stopManipulateCamera()
|
||||
# How big is the node?
|
||||
nodeScale = base.direct.widget.scalingNode.getScale(render)
|
||||
direct = ShowBaseGlobal.direct
|
||||
nodeScale = direct.widget.scalingNode.getScale(ShowBaseGlobal.base.render)
|
||||
maxScale = max(nodeScale[0], nodeScale[1], nodeScale[2])
|
||||
maxDim = min(base.direct.dr.nearWidth, base.direct.dr.nearHeight)
|
||||
maxDim = min(direct.dr.nearWidth, direct.dr.nearHeight)
|
||||
|
||||
# At what distance does the object fill 30% of the screen?
|
||||
# Assuming radius of 1 on widget
|
||||
camY = base.direct.dr.near * (2.0 * maxScale)/(0.3 * maxDim)
|
||||
camY = direct.dr.near * (2.0 * maxScale) / (0.3 * maxDim)
|
||||
|
||||
# What is the vector through the center of the screen?
|
||||
centerVec = Y_AXIS * camY
|
||||
|
||||
# Where is the node relative to the viewpoint
|
||||
vWidget2Camera = base.direct.widget.getPos(base.direct.camera)
|
||||
vWidget2Camera = direct.widget.getPos(direct.camera)
|
||||
|
||||
# How far do you move the camera to be this distance from the node?
|
||||
deltaMove = vWidget2Camera - centerVec
|
||||
|
||||
# Move a target there
|
||||
try:
|
||||
self.camManipRef.setPos(base.direct.camera, deltaMove)
|
||||
self.camManipRef.setPos(direct.camera, deltaMove)
|
||||
except Exception:
|
||||
#self.notify.debug
|
||||
pass
|
||||
|
||||
parent = base.direct.camera.getParent()
|
||||
base.direct.camera.wrtReparentTo(self.camManipRef)
|
||||
ival = base.direct.camera.posInterval(CAM_MOVE_DURATION,
|
||||
Point3(0, 0, 0),
|
||||
blendType = 'easeInOut')
|
||||
parent = direct.camera.getParent()
|
||||
direct.camera.wrtReparentTo(self.camManipRef)
|
||||
ival = direct.camera.posInterval(CAM_MOVE_DURATION,
|
||||
Point3(0, 0, 0),
|
||||
blendType='easeInOut')
|
||||
ival = Sequence(ival, Func(self.reparentCam, parent),
|
||||
name = 'manipulateCamera')
|
||||
self.__startManipulateCamera(ival = ival)
|
||||
name='manipulateCamera')
|
||||
self.__startManipulateCamera(ival=ival)
|
||||
|
||||
def moveToFit(self):
|
||||
# How big is the active widget?
|
||||
widgetScale = base.direct.widget.scalingNode.getScale(render)
|
||||
direct = ShowBaseGlobal.direct
|
||||
widgetScale = direct.widget.scalingNode.getScale(ShowBaseGlobal.base.render)
|
||||
maxScale = max(widgetScale[0], widgetScale[1], widgetScale[2])
|
||||
# At what distance does the widget fill 50% of the screen?
|
||||
camY = ((2 * base.direct.dr.near * (1.5 * maxScale)) /
|
||||
min(base.direct.dr.nearWidth, base.direct.dr.nearHeight))
|
||||
camY = ((2 * direct.dr.near * (1.5 * maxScale)) /
|
||||
min(direct.dr.nearWidth, direct.dr.nearHeight))
|
||||
# Find a point this distance along the Y axis
|
||||
# MRM: This needs to be generalized to support non uniform frusta
|
||||
centerVec = Y_AXIS * camY
|
||||
# Before moving, record the relationship between the selected nodes
|
||||
# and the widget, so that this can be maintained
|
||||
base.direct.selected.getWrtAll()
|
||||
direct.selected.getWrtAll()
|
||||
# Push state onto undo stack
|
||||
base.direct.pushUndo(base.direct.selected)
|
||||
direct.pushUndo(direct.selected)
|
||||
# Remove the task to keep the widget attached to the object
|
||||
taskMgr.remove('followSelectedNodePath')
|
||||
# Spawn a task to keep the selected objects with the widget
|
||||
taskMgr.add(self.stickToWidgetTask, 'stickToWidget')
|
||||
# Spawn a task to move the widget
|
||||
ival = base.direct.widget.posInterval(CAM_MOVE_DURATION,
|
||||
Point3(centerVec),
|
||||
other = base.direct.camera,
|
||||
blendType = 'easeInOut')
|
||||
ival = direct.widget.posInterval(CAM_MOVE_DURATION,
|
||||
Point3(centerVec),
|
||||
other=direct.camera,
|
||||
blendType='easeInOut')
|
||||
ival = Sequence(ival, Func(lambda: taskMgr.remove('stickToWidget')),
|
||||
name = 'moveToFit')
|
||||
ival.start()
|
||||
|
||||
def stickToWidgetTask(self, state):
|
||||
# Move the objects with the widget
|
||||
base.direct.selected.moveWrtWidgetAll()
|
||||
ShowBaseGlobal.direct.selected.moveWrtWidgetAll()
|
||||
# Continue
|
||||
return Task.cont
|
||||
|
||||
def enableMouseFly(self, fKeyEvents = 1):
|
||||
# disable C++ fly interface
|
||||
base = ShowBaseGlobal.base
|
||||
base.disableMouse()
|
||||
# Enable events
|
||||
for event in self.actionEvents:
|
||||
|
|
@ -877,11 +898,11 @@ class DirectCameraControl(DirectObject):
|
|||
for event in self.keyEvents:
|
||||
self.accept(event[0], event[1], extraArgs = event[2:])
|
||||
# Show marker
|
||||
self.coaMarker.reparentTo(base.direct.group)
|
||||
self.coaMarker.reparentTo(ShowBaseGlobal.direct.group)
|
||||
|
||||
def disableMouseFly(self):
|
||||
# Hide the marker
|
||||
self.coaMarker.reparentTo(hidden)
|
||||
self.coaMarker.reparentTo(ShowBaseGlobal.hidden)
|
||||
# Ignore events
|
||||
for event in self.actionEvents:
|
||||
self.ignore(event[0])
|
||||
|
|
@ -890,7 +911,7 @@ class DirectCameraControl(DirectObject):
|
|||
# Kill tasks
|
||||
self.removeManipulateCameraTask()
|
||||
taskMgr.remove('stickToWidget')
|
||||
base.enableMouse()
|
||||
ShowBaseGlobal.base.enableMouse()
|
||||
|
||||
def removeManipulateCameraTask(self):
|
||||
self.__stopManipulateCamera()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import math
|
||||
from panda3d.core import NodePath, Point3, VBase4
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
from .DirectUtil import ROUND_TO, useDirectRenderStyle
|
||||
from .DirectGeometry import LineNodePath
|
||||
|
||||
|
|
@ -14,7 +15,7 @@ class DirectGrid(NodePath, DirectObject):
|
|||
|
||||
# Load up grid parts to initialize grid object
|
||||
# Polygon used to mark grid plane
|
||||
self.gridBack = base.loader.loadModel('models/misc/gridBack')
|
||||
self.gridBack = ShowBaseGlobal.loader.loadModel('models/misc/gridBack')
|
||||
self.gridBack.reparentTo(self)
|
||||
self.gridBack.setColor(*planeColor)
|
||||
|
||||
|
|
@ -36,7 +37,7 @@ class DirectGrid(NodePath, DirectObject):
|
|||
self.centerLines.setThickness(3)
|
||||
|
||||
# Small marker to hilight snap-to-grid point
|
||||
self.snapMarker = base.loader.loadModel('models/misc/sphere')
|
||||
self.snapMarker = ShowBaseGlobal.loader.loadModel('models/misc/sphere')
|
||||
self.snapMarker.node().setName('gridSnapMarker')
|
||||
self.snapMarker.reparentTo(self)
|
||||
self.snapMarker.setColor(1, 0, 0, 1)
|
||||
|
|
@ -55,7 +56,7 @@ class DirectGrid(NodePath, DirectObject):
|
|||
if parent:
|
||||
self.reparentTo(parent)
|
||||
else:
|
||||
self.reparentTo(base.direct.group)
|
||||
self.reparentTo(ShowBaseGlobal.direct.group)
|
||||
|
||||
self.updateGrid()
|
||||
self.fEnabled = 1
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -5,6 +5,7 @@ from panda3d.core import (
|
|||
ConfigVariableBool,
|
||||
ConfigVariableString,
|
||||
CSDefault,
|
||||
GraphicsWindow,
|
||||
NodePath,
|
||||
Point3,
|
||||
TextNode,
|
||||
|
|
@ -35,19 +36,33 @@ from direct.gui import OnscreenText
|
|||
from direct.interval.IntervalGlobal import Func, Sequence
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
from direct.showbase.MessengerGlobal import messenger
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
from direct.showbase.ShowBaseGlobal import ShowBase, hidden
|
||||
|
||||
import builtins
|
||||
|
||||
base: ShowBase
|
||||
|
||||
class DirectSession(DirectObject):
|
||||
|
||||
# post this to the bboard to make sure DIRECT doesn't turn on
|
||||
DIRECTdisablePost = 'disableDIRECT'
|
||||
|
||||
cam: NodePath
|
||||
camera: NodePath
|
||||
oobeCamera: NodePath
|
||||
|
||||
def __init__(self):
|
||||
# Establish a global pointer to the direct object early on
|
||||
# so dependant classes can access it in their code
|
||||
__builtins__["direct"] = base.direct = self
|
||||
global direct, base
|
||||
base = ShowBaseGlobal.base
|
||||
base.direct = self
|
||||
setattr(builtins, 'direct', self)
|
||||
ShowBaseGlobal.direct = self
|
||||
|
||||
# These come early since they are used later on
|
||||
self.group = render.attachNewNode('DIRECT')
|
||||
self.group = base.render.attachNewNode('DIRECT')
|
||||
self.font = TextNode.getDefaultFont()
|
||||
self.fEnabled = 0
|
||||
self.fEnabledLight = 0
|
||||
|
|
@ -57,7 +72,7 @@ class DirectSession(DirectObject):
|
|||
self.drList = DisplayRegionList()
|
||||
self.iRayList = [x.iRay for x in self.drList]
|
||||
self.dr = self.drList[0]
|
||||
self.win = base.win
|
||||
self.win: GraphicsWindow = base.win
|
||||
self.camera = base.camera
|
||||
self.cam = base.cam
|
||||
self.camNode = base.camNode
|
||||
|
|
@ -70,7 +85,7 @@ class DirectSession(DirectObject):
|
|||
self.useObjectHandles()
|
||||
self.grid = DirectGrid()
|
||||
self.grid.disable()
|
||||
self.lights = DirectLights(base.direct.group)
|
||||
self.lights = DirectLights(self.group)
|
||||
# Create some default lights
|
||||
self.lights.createDefaultLights()
|
||||
# But turn them off
|
||||
|
|
@ -308,13 +323,16 @@ class DirectSession(DirectObject):
|
|||
if base.wantTk:
|
||||
from direct.tkpanels import DirectSessionPanel
|
||||
self.panel = DirectSessionPanel.DirectSessionPanel(parent = base.tkRoot)
|
||||
try:
|
||||
|
||||
clusterMode: str
|
||||
if hasattr(builtins, 'clusterMode'):
|
||||
# Has the clusterMode been set externally (i.e. via the
|
||||
# bootstrap application?
|
||||
self.clusterMode = clusterMode
|
||||
except NameError:
|
||||
clusterMode = builtins.clusterMode
|
||||
else:
|
||||
# Has the clusterMode been set via a config variable?
|
||||
self.clusterMode = ConfigVariableString("cluster-mode", '').value
|
||||
clusterMode = ConfigVariableString("cluster-mode", '').value
|
||||
self.clusterMode = clusterMode
|
||||
|
||||
if self.clusterMode == 'client':
|
||||
from direct.cluster.ClusterClient import createClusterClient
|
||||
|
|
@ -325,7 +343,7 @@ class DirectSession(DirectObject):
|
|||
else:
|
||||
from direct.cluster.ClusterClient import DummyClusterClient
|
||||
self.cluster = DummyClusterClient()
|
||||
__builtins__['cluster'] = self.cluster
|
||||
setattr(builtins, 'cluster', self.cluster)
|
||||
|
||||
def addPassThroughKey(self,key):
|
||||
|
||||
|
|
@ -412,10 +430,10 @@ class DirectSession(DirectObject):
|
|||
|
||||
if self.oobeMode:
|
||||
# Position a target point to lerp the oobe camera to
|
||||
base.direct.cameraControl.camManipRef.setPosHpr(self.trueCamera, 0, 0, 0, 0, 0, 0)
|
||||
self.cameraControl.camManipRef.setPosHpr(self.trueCamera, 0, 0, 0, 0, 0, 0)
|
||||
ival = self.oobeCamera.posHprInterval(
|
||||
2.0, pos = Point3(0), hpr = Vec3(0),
|
||||
other = base.direct.cameraControl.camManipRef,
|
||||
other = self.cameraControl.camManipRef,
|
||||
blendType = 'easeInOut')
|
||||
ival = Sequence(ival, Func(self.endOOBE), name = 'oobeTransition')
|
||||
ival.start()
|
||||
|
|
@ -432,20 +450,20 @@ class DirectSession(DirectObject):
|
|||
# Put camera under new oobe camera
|
||||
self.cam.reparentTo(self.oobeCamera)
|
||||
# Position a target point to lerp the oobe camera to
|
||||
base.direct.cameraControl.camManipRef.setPos(
|
||||
self.cameraControl.camManipRef.setPos(
|
||||
self.trueCamera, Vec3(-2, -20, 5))
|
||||
base.direct.cameraControl.camManipRef.lookAt(self.trueCamera)
|
||||
self.cameraControl.camManipRef.lookAt(self.trueCamera)
|
||||
ival = self.oobeCamera.posHprInterval(
|
||||
2.0, pos = Point3(0), hpr = Vec3(0),
|
||||
other = base.direct.cameraControl.camManipRef,
|
||||
other = self.cameraControl.camManipRef,
|
||||
blendType = 'easeInOut')
|
||||
ival = Sequence(ival, Func(self.beginOOBE), name = 'oobeTransition')
|
||||
ival.start()
|
||||
|
||||
def beginOOBE(self):
|
||||
# Make sure we've reached our final destination
|
||||
self.oobeCamera.setPosHpr(base.direct.cameraControl.camManipRef, 0, 0, 0, 0, 0, 0)
|
||||
base.direct.camera = self.oobeCamera
|
||||
self.oobeCamera.setPosHpr(self.cameraControl.camManipRef, 0, 0, 0, 0, 0, 0)
|
||||
self.camera = self.oobeCamera
|
||||
self.oobeMode = 1
|
||||
|
||||
def endOOBE(self):
|
||||
|
|
@ -453,7 +471,7 @@ class DirectSession(DirectObject):
|
|||
self.oobeCamera.setPosHpr(self.trueCamera, 0, 0, 0, 0, 0, 0)
|
||||
# Disable OOBE mode.
|
||||
self.cam.reparentTo(self.trueCamera)
|
||||
base.direct.camera = self.trueCamera
|
||||
self.camera = self.trueCamera
|
||||
# Get rid of ancillary node paths
|
||||
self.oobeVis.reparentTo(hidden)
|
||||
self.oobeCamera.reparentTo(hidden)
|
||||
|
|
@ -501,7 +519,7 @@ class DirectSession(DirectObject):
|
|||
def inputHandler(self, input):
|
||||
if not hasattr(self, 'oobeMode') or self.oobeMode == 0:
|
||||
# [gjeon] change current camera dr, iRay, mouseWatcher accordingly to support multiple windows
|
||||
if base.direct.manipulationControl.fMultiView:
|
||||
if self.manipulationControl.fMultiView:
|
||||
# handling orphan events
|
||||
if self.fMouse1 and 'mouse1' not in input or\
|
||||
self.fMouse2 and 'mouse2' not in input or\
|
||||
|
|
@ -518,7 +536,7 @@ class DirectSession(DirectObject):
|
|||
return
|
||||
|
||||
if (self.fMouse1 or self.fMouse2 or self.fMouse3) and\
|
||||
input[4:7] != base.direct.camera.getName()[:3] and\
|
||||
input[4:7] != self.camera.getName()[:3] and\
|
||||
input.endswith('-up'):
|
||||
# to handle orphan events
|
||||
return
|
||||
|
|
@ -551,14 +569,14 @@ class DirectSession(DirectObject):
|
|||
self.cam = NodePath(winCtrl.camNode)
|
||||
self.camNode = winCtrl.camNode
|
||||
if hasattr(winCtrl, 'grid'):
|
||||
base.direct.grid = winCtrl.grid
|
||||
base.direct.dr = base.direct.drList[base.camList.index(NodePath(winCtrl.camNode))]
|
||||
base.direct.iRay = base.direct.dr.iRay
|
||||
self.grid = winCtrl.grid
|
||||
self.dr = self.drList[base.camList.index(NodePath(winCtrl.camNode))]
|
||||
self.iRay = self.dr.iRay
|
||||
base.mouseWatcher = winCtrl.mouseWatcher
|
||||
base.mouseWatcherNode = winCtrl.mouseWatcher.node()
|
||||
base.direct.dr.mouseUpdate()
|
||||
self.dr.mouseUpdate()
|
||||
DG.LE_showInOneCam(self.selectedNPReadout, self.camera.getName())
|
||||
base.direct.widget = base.direct.manipulationControl.widgetList[base.camList.index(NodePath(winCtrl.camNode))]
|
||||
self.widget = self.manipulationControl.widgetList[base.camList.index(NodePath(winCtrl.camNode))]
|
||||
|
||||
input = input[8:] # get rid of camera prefix
|
||||
if self.fAlt and 'alt' not in input and not input.endswith('-up'):
|
||||
|
|
@ -683,20 +701,18 @@ class DirectSession(DirectObject):
|
|||
if not taskMgr.hasTaskNamed('resizeObjectHandles'):
|
||||
dnp = self.selected.last
|
||||
if dnp:
|
||||
direct = base.direct
|
||||
|
||||
if self.manipulationControl.fMultiView:
|
||||
for i in range(3):
|
||||
sf = 30.0 * direct.drList[i].orthoFactor
|
||||
sf = 30.0 * self.drList[i].orthoFactor
|
||||
self.manipulationControl.widgetList[i].setDirectScalingFactor(sf)
|
||||
|
||||
nodeCamDist = Vec3(dnp.getPos(base.camList[3])).length()
|
||||
sf = 0.075 * nodeCamDist * math.tan(deg2Rad(direct.drList[3].fovV))
|
||||
sf = 0.075 * nodeCamDist * math.tan(deg2Rad(self.drList[3].fovV))
|
||||
self.manipulationControl.widgetList[3].setDirectScalingFactor(sf)
|
||||
|
||||
else:
|
||||
nodeCamDist = Vec3(dnp.getPos(direct.camera)).length()
|
||||
sf = 0.075 * nodeCamDist * math.tan(deg2Rad(direct.drList.getCurrentDr().fovV))
|
||||
nodeCamDist = Vec3(dnp.getPos(self.camera)).length()
|
||||
sf = 0.075 * nodeCamDist * math.tan(deg2Rad(self.drList.getCurrentDr().fovV))
|
||||
self.widget.setDirectScalingFactor(sf)
|
||||
return Task.cont
|
||||
|
||||
|
|
@ -755,7 +771,7 @@ class DirectSession(DirectObject):
|
|||
messenger.send('DIRECT_selectedNodePath_fMulti_fTag_fLEPane', [dnp, fMultiSelect, fSelectTag, fLEPane])
|
||||
|
||||
def followSelectedNodePathTask(self, state):
|
||||
mCoa2Render = state.dnp.mCoa2Dnp * state.dnp.getMat(render)
|
||||
mCoa2Render = state.dnp.mCoa2Dnp * state.dnp.getMat(base.render)
|
||||
decomposeMatrix(mCoa2Render,
|
||||
self.scale, self.hpr, self.pos,
|
||||
CSDefault)
|
||||
|
|
@ -874,7 +890,7 @@ class DirectSession(DirectObject):
|
|||
if nodePath == 'None Given':
|
||||
# If nothing specified, try selected node path
|
||||
nodePath = self.selected.last
|
||||
base.direct.select(nodePath)
|
||||
self.select(nodePath)
|
||||
|
||||
def fitTask(state, self = self):
|
||||
self.cameraControl.fitOnWidget()
|
||||
|
|
@ -1061,7 +1077,7 @@ class DirectSession(DirectObject):
|
|||
|
||||
def useObjectHandles(self):
|
||||
self.widget = self.manipulationControl.objectHandles
|
||||
self.widget.reparentTo(base.direct.group)
|
||||
self.widget.reparentTo(self.group)
|
||||
|
||||
def hideSelectedNPReadout(self):
|
||||
self.selectedNPReadout.reparentTo(hidden)
|
||||
|
|
@ -1167,14 +1183,14 @@ class DisplayRegionContext(DirectObject):
|
|||
self.camLens.setFov(hfov, vfov)
|
||||
|
||||
def getWidth(self):
|
||||
prop = base.direct.win.getProperties()
|
||||
prop = ShowBaseGlobal.direct.win.getProperties()
|
||||
if prop.hasSize():
|
||||
return prop.getXSize()
|
||||
else:
|
||||
return 640
|
||||
|
||||
def getHeight(self):
|
||||
prop = base.direct.win.getProperties()
|
||||
prop = ShowBaseGlobal.direct.win.getProperties()
|
||||
if prop.hasSize():
|
||||
return prop.getYSize()
|
||||
else:
|
||||
|
|
@ -1208,9 +1224,10 @@ class DisplayRegionContext(DirectObject):
|
|||
|
||||
# Values for this frame
|
||||
# This ranges from -1 to 1
|
||||
if base.mouseWatcherNode and base.mouseWatcherNode.hasMouse():
|
||||
self.mouseX = base.mouseWatcherNode.getMouseX()
|
||||
self.mouseY = base.mouseWatcherNode.getMouseY()
|
||||
mouseWatcherNode = base.mouseWatcherNode
|
||||
if mouseWatcherNode and mouseWatcherNode.hasMouse():
|
||||
self.mouseX = mouseWatcherNode.getMouseX()
|
||||
self.mouseY = mouseWatcherNode.getMouseY()
|
||||
self.mouseX = (self.mouseX-self.originX)*self.scaleX
|
||||
self.mouseY = (self.mouseY-self.originY)*self.scaleY
|
||||
# Delta percent of window the mouse moved
|
||||
|
|
@ -1262,6 +1279,9 @@ class DisplayRegionList(DirectObject):
|
|||
def __len__(self):
|
||||
return len(self.displayRegionList)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.displayRegionList)
|
||||
|
||||
def updateContext(self):
|
||||
self.contextTask(None)
|
||||
|
||||
|
|
@ -1296,7 +1316,7 @@ class DisplayRegionList(DirectObject):
|
|||
|
||||
def getCurrentDr(self):
|
||||
if not self.tryToGetCurrentDr:
|
||||
return base.direct.dr
|
||||
return ShowBaseGlobal.direct.dr
|
||||
for dr in self.displayRegionList:
|
||||
if (dr.mouseX >= -1.0 and dr.mouseX <= 1.0 and
|
||||
dr.mouseY >= -1.0 and dr.mouseY <= 1.0):
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import modulefinder
|
|||
import sys
|
||||
import os
|
||||
import marshal
|
||||
import imp
|
||||
import platform
|
||||
import struct
|
||||
import io
|
||||
|
|
@ -13,6 +12,7 @@ import sysconfig
|
|||
import zipfile
|
||||
import importlib
|
||||
import warnings
|
||||
from importlib import machinery
|
||||
|
||||
from . import pefile
|
||||
|
||||
|
|
@ -24,6 +24,16 @@ except ImportError:
|
|||
|
||||
from panda3d.core import Filename, Multifile, PandaSystem, StringStream
|
||||
|
||||
# Old imp constants.
|
||||
_PY_SOURCE = 1
|
||||
_PY_COMPILED = 2
|
||||
_C_EXTENSION = 3
|
||||
_PKG_DIRECTORY = 5
|
||||
_C_BUILTIN = 6
|
||||
_PY_FROZEN = 7
|
||||
|
||||
_PKG_NAMESPACE_DIRECTORY = object()
|
||||
|
||||
# Check to see if we are running python_d, which implies we have a
|
||||
# debug build, and we have to build the module with debug options.
|
||||
# This is only relevant on Windows.
|
||||
|
|
@ -37,7 +47,7 @@ isDebugBuild = (python.lower().endswith('_d'))
|
|||
# NB. if encodings are removed, be sure to remove them from the shortcut in
|
||||
# deploy-stub.c.
|
||||
startupModules = [
|
||||
'imp', 'encodings', 'encodings.*', 'io', 'marshal', 'importlib.machinery',
|
||||
'encodings', 'encodings.*', 'io', 'marshal', 'importlib.machinery',
|
||||
'importlib.util',
|
||||
]
|
||||
|
||||
|
|
@ -262,10 +272,15 @@ class CompilationEnvironment:
|
|||
self.arch = '-arch x86_64'
|
||||
elif proc in ('arm64', 'aarch64'):
|
||||
self.arch = '-arch arm64'
|
||||
self.compileObjExe = "gcc -c %(arch)s -o %(basename)s.o -O2 -I%(pythonIPath)s %(filename)s"
|
||||
self.compileObjDll = "gcc -fPIC -c %(arch)s -o %(basename)s.o -O2 -I%(pythonIPath)s %(filename)s"
|
||||
self.linkExe = "gcc %(arch)s -o %(basename)s %(basename)s.o -framework Python"
|
||||
self.linkDll = "gcc %(arch)s -undefined dynamic_lookup -bundle -o %(basename)s.so %(basename)s.o"
|
||||
self.compileObjExe = "clang -c %(arch)s -o %(basename)s.o -O2 -I%(pythonIPath)s %(filename)s"
|
||||
self.compileObjDll = "clang -fPIC -c %(arch)s -o %(basename)s.o -O2 -I%(pythonIPath)s %(filename)s"
|
||||
self.linkExe = "clang %(arch)s -o %(basename)s %(basename)s.o"
|
||||
if '/Python.framework/' in self.PythonIPath:
|
||||
framework_dir = self.PythonIPath.split("/Python.framework/", 1)[0]
|
||||
if framework_dir != "/System/Library/Frameworks":
|
||||
self.linkExe += " -F " + framework_dir
|
||||
self.linkExe += " -framework Python"
|
||||
self.linkDll = "clang %(arch)s -undefined dynamic_lookup -bundle -o %(basename)s.so %(basename)s.o"
|
||||
|
||||
else:
|
||||
# Unix
|
||||
|
|
@ -897,12 +912,11 @@ class Freezer:
|
|||
|
||||
# Suffix/extension for Python C extension modules
|
||||
if self.platform == PandaSystem.getPlatform():
|
||||
suffixes = imp.get_suffixes()
|
||||
|
||||
# Set extension for Python files to binary mode
|
||||
for i, suffix in enumerate(suffixes):
|
||||
if suffix[2] == imp.PY_SOURCE:
|
||||
suffixes[i] = (suffix[0], 'rb', imp.PY_SOURCE)
|
||||
suffixes = (
|
||||
[(s, 'rb', _C_EXTENSION) for s in machinery.EXTENSION_SUFFIXES] +
|
||||
[(s, 'rb', _PY_SOURCE) for s in machinery.SOURCE_SUFFIXES] +
|
||||
[(s, 'rb', _PY_COMPILED) for s in machinery.BYTECODE_SUFFIXES]
|
||||
)
|
||||
else:
|
||||
suffixes = [('.py', 'rb', 1), ('.pyc', 'rb', 2)]
|
||||
|
||||
|
|
@ -1316,10 +1330,10 @@ class Freezer:
|
|||
ext = mdef.filename.getExtension()
|
||||
if ext == 'pyc' or ext == 'pyo':
|
||||
fp = open(pathname, 'rb')
|
||||
stuff = ("", "rb", imp.PY_COMPILED)
|
||||
stuff = ("", "rb", _PY_COMPILED)
|
||||
self.mf.load_module(mdef.moduleName, fp, pathname, stuff)
|
||||
else:
|
||||
stuff = ("", "rb", imp.PY_SOURCE)
|
||||
stuff = ("", "rb", _PY_SOURCE)
|
||||
if mdef.text:
|
||||
fp = io.StringIO(mdef.text)
|
||||
else:
|
||||
|
|
@ -1415,7 +1429,7 @@ class Freezer:
|
|||
|
||||
def __addPyc(self, multifile, filename, code, compressionLevel):
|
||||
if code:
|
||||
data = imp.get_magic() + b'\0\0\0\0\0\0\0\0'
|
||||
data = importlib.util.MAGIC_NUMBER + b'\0\0\0\0\0\0\0\0'
|
||||
data += marshal.dumps(code)
|
||||
|
||||
stream = StringStream(data)
|
||||
|
|
@ -1605,7 +1619,7 @@ class Freezer:
|
|||
# trouble importing it as a builtin module. Synthesize a frozen
|
||||
# module that loads it as builtin.
|
||||
if '.' in moduleName and self.linkExtensionModules:
|
||||
code = compile('import sys;del sys.modules["%s"];import imp;imp.init_builtin("%s")' % (moduleName, moduleName), moduleName, 'exec', optimize=self.optimize)
|
||||
code = compile('import sys;del sys.modules["%s"];from importlib._bootstrap import _builtin_from_name;_builtin_from_name("%s")' % (moduleName, moduleName), moduleName, 'exec', optimize=self.optimize)
|
||||
code = marshal.dumps(code)
|
||||
mangledName = self.mangleName(moduleName)
|
||||
moduleDefs.append(self.makeModuleDef(mangledName, code))
|
||||
|
|
@ -1887,9 +1901,19 @@ class Freezer:
|
|||
if '.' in moduleName and not self.platform.startswith('android'):
|
||||
if self.platform.startswith("macosx") and not use_console:
|
||||
# We write the Frameworks directory to sys.path[0].
|
||||
code = 'import sys;del sys.modules["%s"];import sys,os,imp;imp.load_dynamic("%s",os.path.join(sys.path[0], "%s%s"))' % (moduleName, moduleName, moduleName, modext)
|
||||
direxpr = 'sys.path[0]'
|
||||
else:
|
||||
code = 'import sys;del sys.modules["%s"];import sys,os,imp;imp.load_dynamic("%s",os.path.join(os.path.dirname(sys.executable), "%s%s"))' % (moduleName, moduleName, moduleName, modext)
|
||||
direxpr = 'os.path.dirname(sys.executable)'
|
||||
|
||||
code = \
|
||||
f'import sys;' \
|
||||
f'del sys.modules["{moduleName}"];' \
|
||||
f'import sys,os;' \
|
||||
f'from importlib.machinery import ExtensionFileLoader,ModuleSpec;' \
|
||||
f'from importlib._bootstrap import _load;' \
|
||||
f'path=os.path.join({direxpr}, "{moduleName}{modext}");' \
|
||||
f'_load(ModuleSpec(name="{moduleName}", loader=ExtensionFileLoader("{moduleName}", path), origin=path))'
|
||||
|
||||
code = compile(code, moduleName, 'exec', optimize=self.optimize)
|
||||
code = marshal.dumps(code)
|
||||
moduleList.append((moduleName, len(pool), len(code)))
|
||||
|
|
@ -2400,9 +2424,6 @@ class Freezer:
|
|||
return True
|
||||
|
||||
|
||||
_PKG_NAMESPACE_DIRECTORY = object()
|
||||
|
||||
|
||||
class PandaModuleFinder(modulefinder.ModuleFinder):
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
|
|
@ -2415,7 +2436,12 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
|
|||
|
||||
self.builtin_module_names = kw.pop('builtin_module_names', sys.builtin_module_names)
|
||||
|
||||
self.suffixes = kw.pop('suffixes', imp.get_suffixes())
|
||||
self.suffixes = kw.pop('suffixes', (
|
||||
[(s, 'rb', _C_EXTENSION) for s in machinery.EXTENSION_SUFFIXES] +
|
||||
[(s, 'r', _PY_SOURCE) for s in machinery.SOURCE_SUFFIXES] +
|
||||
[(s, 'rb', _PY_COMPILED) for s in machinery.BYTECODE_SUFFIXES]
|
||||
))
|
||||
|
||||
self.optimize = kw.pop('optimize', -1)
|
||||
|
||||
modulefinder.ModuleFinder.__init__(self, *args, **kw)
|
||||
|
|
@ -2563,7 +2589,7 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
|
|||
|
||||
suffix, mode, type = file_info
|
||||
self.msgin(2, "load_module", fqname, fp and "fp", pathname)
|
||||
if type == imp.PKG_DIRECTORY:
|
||||
if type == _PKG_DIRECTORY:
|
||||
m = self.load_package(fqname, pathname)
|
||||
self.msgout(2, "load_module ->", m)
|
||||
return m
|
||||
|
|
@ -2574,7 +2600,7 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
|
|||
m.__path__ = pathname
|
||||
return m
|
||||
|
||||
if type == imp.PY_SOURCE:
|
||||
if type == _PY_SOURCE:
|
||||
if fqname in overrideModules:
|
||||
# This module has a custom override.
|
||||
code = overrideModules[fqname]
|
||||
|
|
@ -2598,7 +2624,7 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
|
|||
|
||||
code += b'\n' if isinstance(code, bytes) else '\n'
|
||||
co = compile(code, pathname, 'exec', optimize=self.optimize)
|
||||
elif type == imp.PY_COMPILED:
|
||||
elif type == _PY_COMPILED:
|
||||
if sys.version_info >= (3, 7):
|
||||
try:
|
||||
data = fp.read()
|
||||
|
|
@ -2752,11 +2778,11 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
|
|||
|
||||
# If we have a custom override for this module, we know we have it.
|
||||
if fullname in overrideModules:
|
||||
return (None, '', ('.py', 'r', imp.PY_SOURCE))
|
||||
return (None, '', ('.py', 'r', _PY_SOURCE))
|
||||
|
||||
# It's built into the interpreter.
|
||||
if fullname in self.builtin_module_names:
|
||||
return (None, None, ('', '', imp.C_BUILTIN))
|
||||
return (None, None, ('', '', _C_BUILTIN))
|
||||
|
||||
# If no search path is given, look for a built-in module.
|
||||
if path is None:
|
||||
|
|
@ -2806,7 +2832,7 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
|
|||
for suffix, mode, _ in self.suffixes:
|
||||
init = os.path.join(basename, '__init__' + suffix)
|
||||
if self._open_file(init, mode):
|
||||
return (None, basename, ('', '', imp.PKG_DIRECTORY))
|
||||
return (None, basename, ('', '', _PKG_DIRECTORY))
|
||||
|
||||
# This may be a namespace package.
|
||||
if self._dir_exists(basename):
|
||||
|
|
@ -2818,7 +2844,7 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
|
|||
# Only if we're not looking on a particular path, though.
|
||||
if p3extend_frozen and p3extend_frozen.is_frozen_module(name):
|
||||
# It's a frozen module.
|
||||
return (None, name, ('', '', imp.PY_FROZEN))
|
||||
return (None, name, ('', '', _PY_FROZEN))
|
||||
|
||||
# If we found folders on the path with this module name without an
|
||||
# __init__.py file, we should consider this a namespace package.
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import re
|
|||
import shutil
|
||||
import stat
|
||||
import struct
|
||||
import imp
|
||||
import string
|
||||
import tempfile
|
||||
|
||||
|
|
@ -717,6 +716,7 @@ class build_apps(setuptools.Command):
|
|||
'CFBundlePackageType': 'APPL',
|
||||
'CFBundleSignature': '', #TODO
|
||||
'CFBundleExecutable': self.macos_main_app,
|
||||
'NSHighResolutionCapable': 'True',
|
||||
}
|
||||
|
||||
icon = self.icon_objects.get(
|
||||
|
|
@ -1067,7 +1067,7 @@ class build_apps(setuptools.Command):
|
|||
freezer_extras.update(freezer.extras)
|
||||
freezer_modules.update(freezer.getAllModuleNames())
|
||||
for suffix in freezer.mf.suffixes:
|
||||
if suffix[2] == imp.C_EXTENSION:
|
||||
if suffix[2] == 3: # imp.C_EXTENSION:
|
||||
ext_suffixes.add(suffix[0])
|
||||
|
||||
for appname, scriptname in self.gui_apps.items():
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ GRID_Z_OFFSET = 0.0
|
|||
|
||||
class DistributedCartesianGrid(DistributedNode, CartesianGridBase):
|
||||
notify = directNotify.newCategory("DistributedCartesianGrid")
|
||||
notify.setDebug(0)
|
||||
notify.setDebug(False)
|
||||
|
||||
VisualizeGrid = ConfigVariableBool("visualize-cartesian-grid", False)
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@ if ConfigVariableBool('astron-support', True):
|
|||
CONTROL_REMOVE_RANGE = 9003
|
||||
CONTROL_ADD_POST_REMOVE = 9010
|
||||
CONTROL_CLEAR_POST_REMOVES = 9011
|
||||
CONTROL_SET_CON_NAME = 9012
|
||||
CONTROL_SET_CON_URL = 9013
|
||||
CONTROL_LOG_MESSAGE = 9014
|
||||
|
||||
# State Server control messages:
|
||||
STATESERVER_CREATE_OBJECT_WITH_REQUIRED = 2000
|
||||
|
|
|
|||
|
|
@ -435,7 +435,8 @@ Dtool_funcToMethod(iPosHprScale, NodePath)
|
|||
del iPosHprScale
|
||||
#####################################################################
|
||||
def place(self):
|
||||
base.startDirect(fWantTk = 1)
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
ShowBaseGlobal.base.startDirect(fWantTk = 1)
|
||||
# Don't use a regular import, to prevent ModuleFinder from picking
|
||||
# it up as a dependency when building a .p3d package.
|
||||
import importlib
|
||||
|
|
@ -446,7 +447,8 @@ Dtool_funcToMethod(place, NodePath)
|
|||
del place
|
||||
#####################################################################
|
||||
def explore(self):
|
||||
base.startDirect(fWantTk = 1)
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
ShowBaseGlobal.base.startDirect(fWantTk = 1)
|
||||
# Don't use a regular import, to prevent ModuleFinder from picking
|
||||
# it up as a dependency when building a .p3d package.
|
||||
import importlib
|
||||
|
|
@ -457,7 +459,8 @@ Dtool_funcToMethod(explore, NodePath)
|
|||
del explore
|
||||
#####################################################################
|
||||
def rgbPanel(self, cb = None):
|
||||
base.startTk()
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
ShowBaseGlobal.base.startTk()
|
||||
# Don't use a regular import, to prevent ModuleFinder from picking
|
||||
# it up as a dependency when building a .p3d package.
|
||||
import importlib
|
||||
|
|
@ -468,6 +471,8 @@ Dtool_funcToMethod(rgbPanel, NodePath)
|
|||
del rgbPanel
|
||||
#####################################################################
|
||||
def select(self):
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
base = ShowBaseGlobal.base
|
||||
base.startDirect(fWantTk = 0)
|
||||
base.direct.select(self)
|
||||
|
||||
|
|
@ -475,6 +480,8 @@ Dtool_funcToMethod(select, NodePath)
|
|||
del select
|
||||
#####################################################################
|
||||
def deselect(self):
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
base = ShowBaseGlobal.base
|
||||
base.startDirect(fWantTk = 0)
|
||||
base.direct.deselect(self)
|
||||
|
||||
|
|
@ -676,7 +683,8 @@ def flattenMultitex(self, stateFrom = None, target = None,
|
|||
mr.setAllowTexMat(allowTexMat)
|
||||
|
||||
if win is None:
|
||||
win = base.win
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
win = ShowBaseGlobal.base.win
|
||||
|
||||
if stateFrom is None:
|
||||
mr.scan(self)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class DirectEntry(DirectFrame):
|
|||
to keyboard buttons
|
||||
"""
|
||||
|
||||
directWtext = ConfigVariableBool('direct-wtext', 1)
|
||||
directWtext = ConfigVariableBool('direct-wtext', True)
|
||||
|
||||
AllowCapNamePrefixes = ("Al", "Ap", "Ben", "De", "Del", "Della", "Delle", "Der", "Di", "Du",
|
||||
"El", "Fitz", "La", "Las", "Le", "Les", "Lo", "Los",
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ class OnscreenText(NodePath):
|
|||
self.__wordwrap = wordwrap
|
||||
|
||||
if decal:
|
||||
textNode.setCardDecal(1)
|
||||
textNode.setCardDecal(True)
|
||||
|
||||
if font is None:
|
||||
font = DGG.getDefaultFont()
|
||||
|
|
|
|||
|
|
@ -10,12 +10,6 @@ from direct.directnotify.DirectNotifyGlobal import directNotify
|
|||
from . import Interval
|
||||
|
||||
|
||||
#############################################################
|
||||
### ###
|
||||
### See examples of function intervals in IntervalTest.py ###
|
||||
### ###
|
||||
#############################################################
|
||||
|
||||
class FunctionInterval(Interval.Interval):
|
||||
# Name counter
|
||||
functionIntervalNum = 1
|
||||
|
|
|
|||
|
|
@ -1,222 +0,0 @@
|
|||
"""Undocumented Module"""
|
||||
|
||||
__all__ = ()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from panda3d.core import Filename, Point3, Vec3
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from direct.showbase.ShowBase import ShowBase
|
||||
from direct.actor.Actor import Actor
|
||||
from direct.directutil import Mopath
|
||||
from direct.showbase.MessengerGlobal import messenger
|
||||
from .ActorInterval import ActorInterval
|
||||
from .FunctionInterval import (
|
||||
AcceptInterval,
|
||||
EventInterval,
|
||||
FunctionInterval,
|
||||
IgnoreInterval,
|
||||
PosHprInterval,
|
||||
)
|
||||
from .LerpInterval import LerpPosInterval, LerpHprInterval, LerpPosHprInterval
|
||||
from .MopathInterval import MopathInterval
|
||||
from .SoundInterval import SoundInterval
|
||||
from .MetaInterval import PREVIOUS_END, PREVIOUS_START, TRACK_START, Track
|
||||
|
||||
base = ShowBase()
|
||||
|
||||
boat = base.loader.loadModel('models/misc/smiley')
|
||||
boat.reparentTo(base.render)
|
||||
|
||||
donald = Actor()
|
||||
donald.loadModel("phase_6/models/char/donald-wheel-1000")
|
||||
donald.loadAnims({"steer":"phase_6/models/char/donald-wheel-wheel"})
|
||||
donald.reparentTo(boat)
|
||||
|
||||
dock = base.loader.loadModel('models/misc/smiley')
|
||||
dock.reparentTo(base.render)
|
||||
|
||||
sound = base.loader.loadSfx('phase_6/audio/sfx/SZ_DD_waterlap.mp3')
|
||||
foghorn = base.loader.loadSfx('phase_6/audio/sfx/SZ_DD_foghorn.mp3')
|
||||
|
||||
mp = Mopath.Mopath()
|
||||
mp.loadFile(Filename('phase_6/paths/dd-e-w'))
|
||||
|
||||
# Set up the boat
|
||||
boatMopath = MopathInterval(mp, boat, 'boatpath')
|
||||
boatTrack = Track([boatMopath], 'boattrack')
|
||||
BOAT_START = boatTrack.getIntervalStartTime('boatpath')
|
||||
BOAT_END = boatTrack.getIntervalEndTime('boatpath')
|
||||
|
||||
# This will create an anim interval that is posed every frame
|
||||
donaldSteerInterval = ActorInterval(donald, 'steer')
|
||||
# This will create an anim interval that is started at t = 0 and then
|
||||
# loops for 10 seconds
|
||||
donaldLoopInterval = ActorInterval(donald, 'steer', loop=1, duration = 10.0)
|
||||
donaldSteerTrack = Track([donaldSteerInterval, donaldLoopInterval],
|
||||
name = 'steerTrack')
|
||||
|
||||
# Make the dock lerp up so that it's up when the boat reaches the end of
|
||||
# its mopath
|
||||
dockLerp = LerpPosHprInterval(dock, 5.0,
|
||||
pos=Point3(0, 0, -5),
|
||||
hpr=Vec3(0, 0, 0),
|
||||
name='dock-lerp')
|
||||
# We need the dock's state to be defined before the lerp
|
||||
dockPos = PosHprInterval(dock, dock.getPos(), dock.getHpr(), 1.0, 'dockpos')
|
||||
dockUpTime = BOAT_END - dockLerp.getDuration()
|
||||
hpr2 = Vec3(90.0, 90.0, 90.0)
|
||||
dockLerp2 = LerpHprInterval(dock, 3.0, hpr2, name='hpr-lerp')
|
||||
dockTrack = Track([dockLerp2, dockPos, dockLerp], 'docktrack')
|
||||
dockTrack.setIntervalStartTime('dock-lerp', dockUpTime)
|
||||
dockTrack.setIntervalStartTime('hpr-lerp', BOAT_START)
|
||||
|
||||
# Start the water sound 5 seconds after the boat starts moving
|
||||
waterStartTime = BOAT_START + 5.0
|
||||
waterSound = SoundInterval(sound, name='watersound')
|
||||
soundTrack = Track([waterSound], 'soundtrack')
|
||||
soundTrack.setIntervalStartTime('watersound', waterStartTime)
|
||||
|
||||
# Throw an event when the water track ends
|
||||
eventTime = soundTrack.getIntervalEndTime('watersound')
|
||||
waterDone = EventInterval('water-is-done')
|
||||
waterEventTrack = Track([waterDone])
|
||||
waterEventTrack.setIntervalStartTime('water-is-done', eventTime)
|
||||
|
||||
def handleWaterDone():
|
||||
print('water is done')
|
||||
|
||||
# Interval can handle its own event
|
||||
messenger.accept('water-is-done', waterDone, handleWaterDone)
|
||||
|
||||
foghornStartTime = BOAT_START + 4.0
|
||||
foghornSound = SoundInterval(foghorn, name='foghorn')
|
||||
soundTrack2 = Track([(foghornStartTime, foghornSound)], 'soundtrack2')
|
||||
|
||||
mtrack = MultiTrack([boatTrack, dockTrack, soundTrack, soundTrack2, waterEventTrack, # type: ignore[name-defined]
|
||||
donaldSteerTrack])
|
||||
# Print out MultiTrack parameters
|
||||
print(mtrack)
|
||||
|
||||
### Using lambdas and functions ###
|
||||
# Using a lambda
|
||||
i1 = FunctionInterval(lambda: base.transitions.fadeOut())
|
||||
i2 = FunctionInterval(lambda: base.transitions.fadeIn())
|
||||
|
||||
def caughtIt():
|
||||
print('Caught here-is-an-event')
|
||||
|
||||
class DummyAcceptor(DirectObject):
|
||||
pass
|
||||
|
||||
da = DummyAcceptor()
|
||||
i3 = AcceptInterval(da, 'here-is-an-event', caughtIt)
|
||||
|
||||
i4 = EventInterval('here-is-an-event')
|
||||
|
||||
i5 = IgnoreInterval(da, 'here-is-an-event')
|
||||
|
||||
# Using a function
|
||||
def printDone():
|
||||
print('done')
|
||||
|
||||
i6 = FunctionInterval(printDone)
|
||||
|
||||
# Create track
|
||||
t1 = Track([
|
||||
# Fade out
|
||||
(0.0, i1),
|
||||
# Fade in
|
||||
(2.0, i2),
|
||||
# Accept event
|
||||
(4.0, i3),
|
||||
# Throw it,
|
||||
(5.0, i4),
|
||||
# Ignore event
|
||||
(6.0, i5),
|
||||
# Throw event again and see if ignore worked
|
||||
(7.0, i4),
|
||||
# Print done
|
||||
(8.0, i6)], name = 'demo')
|
||||
|
||||
print(t1)
|
||||
|
||||
### Specifying interval start times during track construction ###
|
||||
# Interval start time can be specified relative to three different points:
|
||||
# PREVIOUS_END
|
||||
# PREVIOUS_START
|
||||
# TRACK_START
|
||||
|
||||
startTime = 0.0
|
||||
def printStart():
|
||||
global startTime
|
||||
startTime = base.clock.getFrameTime()
|
||||
print('Start')
|
||||
|
||||
def printPreviousStart():
|
||||
global startTime
|
||||
currTime = base.clock.getFrameTime()
|
||||
print('PREVIOUS_END %0.2f' % (currTime - startTime))
|
||||
|
||||
def printPreviousEnd():
|
||||
global startTime
|
||||
currTime = base.clock.getFrameTime()
|
||||
print('PREVIOUS_END %0.2f' % (currTime - startTime))
|
||||
|
||||
def printTrackStart():
|
||||
global startTime
|
||||
currTime = base.clock.getFrameTime()
|
||||
print('TRACK_START %0.2f' % (currTime - startTime))
|
||||
|
||||
def printArguments(a, b, c):
|
||||
print('My args were %d, %d, %d' % (a, b, c))
|
||||
|
||||
i1 = FunctionInterval(printStart)
|
||||
# Just to take time
|
||||
i2 = LerpPosInterval(base.camera, 2.0, Point3(0, 10, 5))
|
||||
# This will be relative to end of camera move
|
||||
i3 = FunctionInterval(printPreviousEnd) # type: ignore[assignment]
|
||||
# Just to take time
|
||||
i4 = LerpPosInterval(base.camera, 2.0, Point3(0, 0, 5))
|
||||
# This will be relative to the start of the camera move
|
||||
i5 = FunctionInterval(printPreviousStart) # type: ignore[assignment]
|
||||
# This will be relative to track start
|
||||
i6 = FunctionInterval(printTrackStart)
|
||||
# This will print some arguments
|
||||
# This will be relative to track start
|
||||
i7 = FunctionInterval(printArguments, extraArgs = [1, 10, 100])
|
||||
# Create the track, if you don't specify offset type in tuple it defaults to
|
||||
# relative to TRACK_START (first entry below)
|
||||
t2 = Track([(0.0, i1), # i1 start at t = 0, duration = 0.0
|
||||
(1.0, i2, TRACK_START), # i2 start at t = 1, duration = 2.0
|
||||
(2.0, i3, PREVIOUS_END), # i3 start at t = 5, duration = 0.0
|
||||
(1.0, i4, PREVIOUS_END), # i4 start at t = 6, duration = 2.0
|
||||
(3.0, i5, PREVIOUS_START), # i5 start at t = 9, duration = 0.0
|
||||
(10.0, i6, TRACK_START), # i6 start at t = 10, duration = 0.0
|
||||
(12.0, i7)], # i7 start at t = 12, duration = 0.0
|
||||
name = 'startTimeDemo')
|
||||
|
||||
print(t2)
|
||||
|
||||
# Play tracks
|
||||
# mtrack.play()
|
||||
# t1.play()
|
||||
# t2.play()
|
||||
|
||||
|
||||
def test(n):
|
||||
lerps = []
|
||||
for i in range(n):
|
||||
lerps.append(LerpPosHprInterval(dock, 5.0,
|
||||
pos=Point3(0, 0, -5),
|
||||
hpr=Vec3(0, 0, 0),
|
||||
startPos=dock.getPos(),
|
||||
startHpr=dock.getHpr(),
|
||||
name='dock-lerp'))
|
||||
lerps.append(EventInterval("joe"))
|
||||
t = Track(lerps)
|
||||
mt = MultiTrack([t])
|
||||
# return mt
|
||||
|
||||
test(5)
|
||||
base.run()
|
||||
|
|
@ -7,6 +7,7 @@ from direct.wxwidgets.WxPandaShell import WxPandaShell
|
|||
from direct.wxwidgets.WxSlider import WxSlider
|
||||
from direct.directtools.DirectSelection import SelectionRay
|
||||
from direct.showbase.MessengerGlobal import messenger
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
|
||||
#from ViewPort import *
|
||||
from . import ObjectGlobals as OG
|
||||
|
|
@ -88,7 +89,7 @@ class PandaTextDropTarget(wx.TextDropTarget):
|
|||
np = NodePath('temp')
|
||||
np.setPos(self.view.camera, hitPt)
|
||||
|
||||
if base.direct.manipulationControl.fGridSnap:
|
||||
if ShowBaseGlobal.direct.manipulationControl.fGridSnap:
|
||||
snappedPos = self.view.grid.computeSnapPoint(np.getPos())
|
||||
np.setPos(snappedPos)
|
||||
|
||||
|
|
@ -98,10 +99,10 @@ class PandaTextDropTarget(wx.TextDropTarget):
|
|||
|
||||
# transform newobj to cursor position
|
||||
obj = self.editor.objectMgr.findObjectByNodePath(newobj)
|
||||
action = ActionTransformObj(self.editor, obj[OG.OBJ_UID], Mat4(np.getMat()))
|
||||
self.editor.actionMgr.push(action)
|
||||
action2 = ActionTransformObj(self.editor, obj[OG.OBJ_UID], Mat4(np.getMat()))
|
||||
self.editor.actionMgr.push(action2)
|
||||
np.remove()
|
||||
action()
|
||||
action2()
|
||||
iRay.collisionNodePath.removeNode()
|
||||
del iRay
|
||||
|
||||
|
|
@ -250,13 +251,13 @@ class LevelEditorUIBase(WxPandaShell):
|
|||
WxPandaShell.createMenu(self)
|
||||
|
||||
def onGraphEditor(self, e):
|
||||
if base.direct.selected.last is None:
|
||||
if ShowBaseGlobal.direct.selected.last is None:
|
||||
dlg = wx.MessageDialog(None, 'Please select a object first.', 'NOTICE', wx.OK)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
self.graphEditorMenuItem.Check(False)
|
||||
else:
|
||||
currentObj = self.editor.objectMgr.findObjectByNodePath(base.direct.selected.last)
|
||||
currentObj = self.editor.objectMgr.findObjectByNodePath(ShowBaseGlobal.direct.selected.last)
|
||||
self.graphEditorUI = GraphEditorUI(self, self.editor, currentObj)
|
||||
self.graphEditorUI.Show()
|
||||
self.graphEditorMenuItem.Check(True)
|
||||
|
|
@ -298,7 +299,7 @@ class LevelEditorUIBase(WxPandaShell):
|
|||
degreeUI = CurveDegreeUI(self, -1, 'Curve Degree')
|
||||
degreeUI.ShowModal()
|
||||
degreeUI.Destroy()
|
||||
base.direct.manipulationControl.disableManipulation()
|
||||
ShowBaseGlobal.direct.manipulationControl.disableManipulation()
|
||||
self.editCurveMenuItem.Check(False)
|
||||
|
||||
def onEditCurve(self, e):
|
||||
|
|
@ -313,15 +314,15 @@ class LevelEditorUIBase(WxPandaShell):
|
|||
self.createCurveMenuItem.Check(False)
|
||||
self.onEditCurve(None)
|
||||
else:
|
||||
if base.direct.selected.last is None:
|
||||
if ShowBaseGlobal.direct.selected.last is None:
|
||||
dlg = wx.MessageDialog(None, 'Please select a curve first.', 'NOTICE', wx.OK)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
self.editCurveMenuItem.Check(False)
|
||||
if base.direct.selected.last is not None:
|
||||
base.direct.manipulationControl.enableManipulation()
|
||||
if ShowBaseGlobal.direct.selected.last is not None:
|
||||
ShowBaseGlobal.direct.manipulationControl.enableManipulation()
|
||||
self.createCurveMenuItem.Check(False)
|
||||
self.curveObj = self.editor.objectMgr.findObjectByNodePath(base.direct.selected.last)
|
||||
self.curveObj = self.editor.objectMgr.findObjectByNodePath(ShowBaseGlobal.direct.selected.last)
|
||||
if self.curveObj[OG.OBJ_DEF].name == '__Curve__':
|
||||
self.editor.mode = self.editor.EDIT_CURVE_MODE
|
||||
self.editor.updateStatusReadout('Please press ENTER to end the curve editing.')
|
||||
|
|
@ -339,8 +340,8 @@ class LevelEditorUIBase(WxPandaShell):
|
|||
|
||||
def updateMenu(self):
|
||||
hotKeyDict = {}
|
||||
for hotKey in base.direct.hotKeyMap.keys():
|
||||
desc = base.direct.hotKeyMap[hotKey]
|
||||
for hotKey in ShowBaseGlobal.direct.hotKeyMap.keys():
|
||||
desc = ShowBaseGlobal.direct.hotKeyMap[hotKey]
|
||||
hotKeyDict[desc[1]] = hotKey
|
||||
|
||||
for id in self.MENU_TEXTS.keys():
|
||||
|
|
@ -401,16 +402,16 @@ class LevelEditorUIBase(WxPandaShell):
|
|||
else:
|
||||
mpos = evt.GetPosition()
|
||||
|
||||
base.direct.fMouse3 = 0
|
||||
ShowBaseGlobal.direct.fMouse3 = 0
|
||||
self.PopupMenu(self.contextMenu, mpos)
|
||||
|
||||
def onKeyDownEvent(self, evt):
|
||||
if evt.GetKeyCode() == wx.WXK_ALT:
|
||||
base.direct.fAlt = 1
|
||||
ShowBaseGlobal.direct.fAlt = 1
|
||||
elif evt.GetKeyCode() == wx.WXK_CONTROL:
|
||||
base.direct.fControl = 1
|
||||
ShowBaseGlobal.direct.fControl = 1
|
||||
elif evt.GetKeyCode() == wx.WXK_SHIFT:
|
||||
base.direct.fShift = 1
|
||||
ShowBaseGlobal.direct.fShift = 1
|
||||
elif evt.GetKeyCode() == wx.WXK_UP:
|
||||
messenger.send('arrow_up')
|
||||
elif evt.GetKeyCode() == wx.WXK_DOWN:
|
||||
|
|
@ -428,11 +429,11 @@ class LevelEditorUIBase(WxPandaShell):
|
|||
|
||||
def onKeyUpEvent(self, evt):
|
||||
if evt.GetKeyCode() == wx.WXK_ALT:
|
||||
base.direct.fAlt = 0
|
||||
ShowBaseGlobal.direct.fAlt = 0
|
||||
elif evt.GetKeyCode() == wx.WXK_CONTROL:
|
||||
base.direct.fControl = 0
|
||||
ShowBaseGlobal.direct.fControl = 0
|
||||
elif evt.GetKeyCode() == wx.WXK_SHIFT:
|
||||
base.direct.fShift = 0
|
||||
ShowBaseGlobal.direct.fShift = 0
|
||||
elif evt.GetKeyCode() == wx.WXK_UP:
|
||||
messenger.send('arrow_up-up')
|
||||
elif evt.GetKeyCode() == wx.WXK_DOWN:
|
||||
|
|
@ -473,8 +474,8 @@ class LevelEditorUIBase(WxPandaShell):
|
|||
input = 'control-%s'%chr(evt.GetKeyCode())
|
||||
elif evt.GetKeyCode() < 256:
|
||||
input = chr(evt.GetKeyCode())
|
||||
if input in base.direct.hotKeyMap.keys():
|
||||
keyDesc = base.direct.hotKeyMap[input]
|
||||
if input in ShowBaseGlobal.direct.hotKeyMap.keys():
|
||||
keyDesc = ShowBaseGlobal.direct.hotKeyMap[input]
|
||||
messenger.send(keyDesc[1])
|
||||
|
||||
def reset(self):
|
||||
|
|
@ -533,12 +534,12 @@ class LevelEditorUIBase(WxPandaShell):
|
|||
|
||||
def toggleGridSnap(self, evt):
|
||||
if self.gridSnapMenuItem.IsChecked():
|
||||
base.direct.manipulationControl.fGridSnap = 1
|
||||
ShowBaseGlobal.direct.manipulationControl.fGridSnap = 1
|
||||
for grid in [self.perspView.grid, self.topView.grid, self.frontView.grid, self.leftView.grid]:
|
||||
grid.fXyzSnap = 1
|
||||
|
||||
else:
|
||||
base.direct.manipulationControl.fGridSnap = 0
|
||||
ShowBaseGlobal.direct.manipulationControl.fGridSnap = 0
|
||||
for grid in [self.perspView.grid, self.topView.grid, self.frontView.grid, self.leftView.grid]:
|
||||
grid.fXyzSnap = 0
|
||||
|
||||
|
|
@ -589,7 +590,7 @@ class LevelEditorUIBase(WxPandaShell):
|
|||
self.contextMenu.AppendSeparator()
|
||||
|
||||
def replaceObject(self, evt, all=False):
|
||||
currObj = self.editor.objectMgr.findObjectByNodePath(base.direct.selected.last)
|
||||
currObj = self.editor.objectMgr.findObjectByNodePath(ShowBaseGlobal.direct.selected.last)
|
||||
if currObj is None:
|
||||
print('No valid object is selected for replacement')
|
||||
return
|
||||
|
|
@ -636,13 +637,13 @@ class GridSizeUI(wx.Dialog):
|
|||
vbox.Add(okButton, 1, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 5)
|
||||
|
||||
self.SetSizer(vbox)
|
||||
base.le.ui.bindKeyEvents(False)
|
||||
ShowBaseGlobal.base.le.ui.bindKeyEvents(False)
|
||||
|
||||
def onApply(self, evt):
|
||||
newSize = self.gridSizeSlider.GetValue()
|
||||
newSpacing = self.gridSpacingSlider.GetValue()
|
||||
self.parent.updateGrids(newSize, newSpacing)
|
||||
base.le.ui.bindKeyEvents(True)
|
||||
ShowBaseGlobal.base.le.ui.bindKeyEvents(True)
|
||||
self.Destroy()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ class LevelLoader(LevelLoaderBase):
|
|||
|
||||
def initLoader(self):
|
||||
self.defaultPath = os.path.dirname(__file__)
|
||||
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
base = ShowBaseGlobal.base
|
||||
base.objectPalette = ObjectPalette()
|
||||
base.protoPalette = ProtoPalette()
|
||||
base.objectHandler = ObjectHandler(None)
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ class ParticleEffect(NodePath):
|
|||
def addForceGroup(self, forceGroup):
|
||||
forceGroup.nodePath.reparentTo(self)
|
||||
forceGroup.particleEffect = self
|
||||
self.forceGroupDict[forceGroup.getName()] = forceGroup
|
||||
self.forceGroupDict[forceGroup.name] = forceGroup
|
||||
|
||||
# Associate the force group with all particles
|
||||
for force in forceGroup:
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ sound, music, shaders and fonts from disk.
|
|||
__all__ = ['Loader']
|
||||
|
||||
from panda3d.core import (
|
||||
AudioLoadRequest,
|
||||
ConfigVariableBool,
|
||||
Filename,
|
||||
FontPool,
|
||||
|
|
@ -977,6 +976,8 @@ class Loader(DirectObject):
|
|||
just as in loadModel(); otherwise, the loading happens before
|
||||
loadSound() returns."""
|
||||
|
||||
from panda3d.core import AudioLoadRequest
|
||||
|
||||
if not isinstance(soundPath, (tuple, list, set)):
|
||||
# We were given a single sound pathname or a MovieAudio instance.
|
||||
soundList = [soundPath]
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ import builtins
|
|||
builtins.config = DConfig # type: ignore[attr-defined]
|
||||
|
||||
from direct.directnotify.DirectNotifyGlobal import directNotify, giveNotify
|
||||
from direct.directnotify.Notifier import Notifier
|
||||
from .MessengerGlobal import messenger
|
||||
from .BulletinBoardGlobal import bulletinBoard
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
|
|
@ -140,6 +141,7 @@ import importlib
|
|||
from direct.showbase import ExceptionVarDump
|
||||
from . import DirectObject
|
||||
from . import SfxPlayer
|
||||
from typing import ClassVar, Optional
|
||||
if __debug__:
|
||||
from direct.showbase import GarbageReport
|
||||
from direct.directutil import DeltaProfiler
|
||||
|
|
@ -160,8 +162,13 @@ def exitfunc():
|
|||
class ShowBase(DirectObject.DirectObject):
|
||||
|
||||
#: The deprecated `.DConfig` interface for accessing config variables.
|
||||
config = DConfig
|
||||
notify = directNotify.newCategory("ShowBase")
|
||||
config: ClassVar = DConfig
|
||||
notify: ClassVar[Notifier] = directNotify.newCategory("ShowBase")
|
||||
guiItems: ClassVar[dict]
|
||||
|
||||
render2d: NodePath
|
||||
aspect2d: NodePath
|
||||
pixel2d: NodePath
|
||||
|
||||
def __init__(self, fStartDirect=True, windowType=None):
|
||||
"""Opens a window, sets up a 3-D and several 2-D scene graphs, and
|
||||
|
|
@ -337,10 +344,10 @@ class ShowBase(DirectObject.DirectObject):
|
|||
self.tkRootCreated = False
|
||||
|
||||
# This is used for syncing multiple PCs in a distributed cluster
|
||||
try:
|
||||
if hasattr(builtins, 'clusterSyncFlag'):
|
||||
# Has the cluster sync variable been set externally?
|
||||
self.clusterSyncFlag = clusterSyncFlag
|
||||
except NameError:
|
||||
self.clusterSyncFlag = builtins.clusterSyncFlag
|
||||
else:
|
||||
# Has the clusterSyncFlag been set via a config variable
|
||||
self.clusterSyncFlag = ConfigVariableBool('cluster-sync', False)
|
||||
|
||||
|
|
@ -424,6 +431,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
#: `.Loader.Loader` object.
|
||||
self.loader = Loader.Loader(self)
|
||||
self.graphicsEngine.setDefaultLoader(self.loader.loader)
|
||||
ShowBaseGlobal.loader = self.loader
|
||||
|
||||
#: The global event manager, as imported from `.EventManagerGlobal`.
|
||||
self.eventMgr = eventMgr
|
||||
|
|
@ -712,10 +720,9 @@ class ShowBase(DirectObject.DirectObject):
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
if hasattr(self, 'win'):
|
||||
del self.win
|
||||
del self.winList
|
||||
del self.pipe
|
||||
self.win = None
|
||||
self.winList.clear()
|
||||
self.pipe = None
|
||||
|
||||
def makeDefaultPipe(self, printPipeTypes = None):
|
||||
"""
|
||||
|
|
@ -728,7 +735,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
# When the user didn't specify an explicit setting, take the value
|
||||
# from the config variable. We could just omit the parameter, however
|
||||
# this way we can keep backward compatibility.
|
||||
printPipeTypes = ConfigVariableBool("print-pipe-types", True)
|
||||
printPipeTypes = ConfigVariableBool("print-pipe-types", True).value
|
||||
|
||||
selection = GraphicsPipeSelection.getGlobalPtr()
|
||||
if printPipeTypes:
|
||||
|
|
@ -3414,7 +3421,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
# Set fWantTk to 0 to avoid starting Tk with this call
|
||||
self.startDirect(fWantDirect = fDirect, fWantTk = fTk, fWantWx = fWx)
|
||||
|
||||
def run(self): # pylint: disable=method-hidden
|
||||
def run(self) -> None: # pylint: disable=method-hidden
|
||||
"""This method runs the :class:`~direct.task.Task.TaskManager`
|
||||
when ``self.appRunner is None``, which is to say, when we are
|
||||
not running from within a p3d file. When we *are* within a p3d
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@ from panda3d.core import VirtualFileSystem, Notify, ClockObject, PandaSystem
|
|||
from panda3d.core import ConfigPageManager, ConfigVariableManager, ConfigVariableBool
|
||||
from panda3d.core import NodePath, PGTop
|
||||
from . import DConfig as config # pylint: disable=unused-import
|
||||
from .Loader import Loader
|
||||
import warnings
|
||||
|
||||
__dev__ = ConfigVariableBool('want-dev', __debug__).value
|
||||
__dev__: bool = ConfigVariableBool('want-dev', __debug__).value
|
||||
|
||||
base: ShowBase
|
||||
|
||||
|
|
@ -61,6 +62,10 @@ aspect2d = render2d.attachNewNode(PGTop("aspect2d"))
|
|||
#: A dummy scene graph that is not being rendered by anything.
|
||||
hidden = NodePath("hidden")
|
||||
|
||||
loader: Loader
|
||||
|
||||
direct: "DirectSession"
|
||||
|
||||
# Set direct notify categories now that we have config
|
||||
directNotify.setDconfigLevels()
|
||||
|
||||
|
|
|
|||
|
|
@ -37,4 +37,5 @@ del bordercolors
|
|||
|
||||
def spawnTkLoop():
|
||||
"""Alias for :meth:`base.spawnTkLoop() <.ShowBase.spawnTkLoop>`."""
|
||||
base.spawnTkLoop()
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
ShowBaseGlobal.base.spawnTkLoop()
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@
|
|||
|
||||
def spawnWxLoop():
|
||||
"""Alias for :meth:`base.spawnWxLoop() <.ShowBase.spawnWxLoop>`."""
|
||||
base.spawnWxLoop()
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
ShowBaseGlobal.base.spawnWxLoop()
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ from panda3d.core import (
|
|||
WindowProperties,
|
||||
)
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
import math
|
||||
import copy
|
||||
|
|
@ -109,7 +110,7 @@ class TexMemWatcher(DirectObject):
|
|||
# This is the maximum number of bitmask rows (within
|
||||
# self.limit) to allocate for packing. This controls the
|
||||
# value assigned to self.quantize in repack().
|
||||
self.maxHeight = base.config.GetInt('tex-mem-max-height', 300)
|
||||
self.maxHeight = ConfigVariableInt('tex-mem-max-height', 300).value
|
||||
|
||||
# The total number of texture bytes tracked, including overflow.
|
||||
self.totalSize = 0
|
||||
|
|
@ -122,6 +123,7 @@ class TexMemWatcher(DirectObject):
|
|||
self.placedQSize = 0
|
||||
|
||||
# If no GSG is specified, use the main GSG.
|
||||
base = ShowBaseGlobal.base
|
||||
if gsg is None:
|
||||
gsg = base.win.getGsg()
|
||||
elif isinstance(gsg, GraphicsOutput):
|
||||
|
|
@ -150,7 +152,7 @@ class TexMemWatcher(DirectObject):
|
|||
# Set this to tinydisplay if you're running on a machine with
|
||||
# limited texture memory. That way you won't compete for
|
||||
# texture memory with the main scene.
|
||||
moduleName = base.config.GetString('tex-mem-pipe', '')
|
||||
moduleName = ConfigVariableString('tex-mem-pipe', '').value
|
||||
if moduleName:
|
||||
self.pipe = base.makeModulePipe(moduleName)
|
||||
|
||||
|
|
@ -202,7 +204,7 @@ class TexMemWatcher(DirectObject):
|
|||
|
||||
# How frequently should the texture memory window check for
|
||||
# state changes?
|
||||
updateInterval = base.config.GetDouble("tex-mem-update-interval", 0.5)
|
||||
updateInterval = ConfigVariableDouble("tex-mem-update-interval", 0.5).value
|
||||
self.task = taskMgr.doMethodLater(updateInterval, self.updateTextures, 'TexMemWatcher')
|
||||
|
||||
self.setLimit(limit)
|
||||
|
|
@ -380,7 +382,7 @@ class TexMemWatcher(DirectObject):
|
|||
self.cleanedUp = True
|
||||
|
||||
# Remove the window.
|
||||
base.graphicsEngine.removeWindow(self.win)
|
||||
self.win.engine.removeWindow(self.win)
|
||||
self.win = None
|
||||
self.gsg = None
|
||||
self.pipe = None
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class TexViewer(DirectObject):
|
|||
|
||||
# We'll put the full-resolution texture on the left.
|
||||
cm = CardMaker('left')
|
||||
l, r, b, t = (-1, -0.1, 0, 0.9)
|
||||
l, r, b, t = (-1.0, -0.1, 0.0, 0.9)
|
||||
cm.setFrame(l, r, b, t)
|
||||
left = cards.attachNewNode(cm.generate())
|
||||
left.setTexture(self.tex)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ class MiniTask:
|
|||
done = 0
|
||||
cont = 1
|
||||
|
||||
name: str
|
||||
|
||||
def __init__(self, callback):
|
||||
self.__call__ = callback
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ For more information about the task system, consult the
|
|||
:ref:`tasks-and-event-handling` page in the programming manual.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ['Task', 'TaskManager',
|
||||
'cont', 'done', 'again', 'pickup', 'exit',
|
||||
'sequence', 'loop', 'pause']
|
||||
|
|
@ -13,6 +15,7 @@ __all__ = ['Task', 'TaskManager',
|
|||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||
from direct.showbase.PythonUtil import Functor, ScratchPad
|
||||
from direct.showbase.MessengerGlobal import messenger
|
||||
from typing import Any, Callable, Coroutine, Final, Generator, Sequence, TypeVar, Union
|
||||
import types
|
||||
import random
|
||||
import importlib
|
||||
|
|
@ -20,6 +23,7 @@ import sys
|
|||
|
||||
# On Android, there's no use handling SIGINT, and in fact we can't, since we
|
||||
# run the application in a separate thread from the main thread.
|
||||
signal: types.ModuleType | None
|
||||
if hasattr(sys, 'getandroidapilevel'):
|
||||
signal = None
|
||||
else:
|
||||
|
|
@ -41,8 +45,15 @@ from panda3d.core import (
|
|||
)
|
||||
from direct.extensions_native import HTTPChannel_extensions # pylint: disable=unused-import
|
||||
|
||||
# The following variables are typing constructs used in annotations
|
||||
# to succinctly express all the types that can be converted into tasks.
|
||||
_T = TypeVar('_T', covariant=True)
|
||||
_TaskCoroutine = Union[Coroutine[Any, None, _T], Generator[Any, None, _T]]
|
||||
_TaskFunction = Callable[..., Union[int, _TaskCoroutine[Union[int, None]], None]]
|
||||
_FuncOrTask = Union[_TaskFunction, _TaskCoroutine[Any], AsyncTask]
|
||||
|
||||
def print_exc_plus():
|
||||
|
||||
def print_exc_plus() -> None:
|
||||
"""
|
||||
Print the usual traceback information, followed by a listing of all the
|
||||
local variables in each frame.
|
||||
|
|
@ -50,12 +61,13 @@ def print_exc_plus():
|
|||
import traceback
|
||||
|
||||
tb = sys.exc_info()[2]
|
||||
assert tb is not None
|
||||
while 1:
|
||||
if not tb.tb_next:
|
||||
break
|
||||
tb = tb.tb_next
|
||||
stack = []
|
||||
f = tb.tb_frame
|
||||
f: types.FrameType | None = tb.tb_frame
|
||||
while f:
|
||||
stack.append(f)
|
||||
f = f.f_back
|
||||
|
|
@ -82,11 +94,11 @@ def print_exc_plus():
|
|||
# these Python names, and define them both at the module level, here,
|
||||
# and at the class level (below). The preferred access is via the
|
||||
# class level.
|
||||
done = AsyncTask.DSDone
|
||||
cont = AsyncTask.DSCont
|
||||
again = AsyncTask.DSAgain
|
||||
pickup = AsyncTask.DSPickup
|
||||
exit = AsyncTask.DSExit
|
||||
done: Final = AsyncTask.DSDone
|
||||
cont: Final = AsyncTask.DSCont
|
||||
again: Final = AsyncTask.DSAgain
|
||||
pickup: Final = AsyncTask.DSPickup
|
||||
exit: Final = AsyncTask.DSExit
|
||||
|
||||
#: Task aliases to :class:`panda3d.core.PythonTask` for historical purposes.
|
||||
Task = PythonTask
|
||||
|
|
@ -110,7 +122,7 @@ gather = Task.gather
|
|||
shield = Task.shield
|
||||
|
||||
|
||||
def sequence(*taskList):
|
||||
def sequence(*taskList: AsyncTask) -> AsyncTaskSequence:
|
||||
seq = AsyncTaskSequence('sequence')
|
||||
for task in taskList:
|
||||
seq.addTask(task)
|
||||
|
|
@ -120,7 +132,7 @@ def sequence(*taskList):
|
|||
Task.DtoolClassDict['sequence'] = staticmethod(sequence)
|
||||
|
||||
|
||||
def loop(*taskList):
|
||||
def loop(*taskList: AsyncTask) -> AsyncTaskSequence:
|
||||
seq = AsyncTaskSequence('loop')
|
||||
for task in taskList:
|
||||
seq.addTask(task)
|
||||
|
|
@ -140,10 +152,12 @@ class TaskManager:
|
|||
|
||||
MaxEpochSpeed = 1.0/30.0
|
||||
|
||||
def __init__(self):
|
||||
__prevHandler: Any
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.mgr = AsyncTaskManager.getGlobalPtr()
|
||||
|
||||
self.resumeFunc = None
|
||||
self.resumeFunc: Callable[[], object] | None = None
|
||||
self.globalClock = self.mgr.getClock()
|
||||
self.stepping = False
|
||||
self.running = False
|
||||
|
|
@ -153,12 +167,12 @@ class TaskManager:
|
|||
if signal:
|
||||
self.__prevHandler = signal.default_int_handler
|
||||
|
||||
self._frameProfileQueue = []
|
||||
self._frameProfileQueue: list[tuple[int, Any, Callable[[], object] | None]] = []
|
||||
|
||||
# this will be set when it's safe to import StateVar
|
||||
self._profileFrames = None
|
||||
self._profileFrames: Any = None
|
||||
self._frameProfiler = None
|
||||
self._profileTasks = None
|
||||
self._profileTasks: Any = None
|
||||
self._taskProfiler = None
|
||||
self._taskProfileInfo = ScratchPad(
|
||||
taskId = None,
|
||||
|
|
@ -166,7 +180,7 @@ class TaskManager:
|
|||
session = None,
|
||||
)
|
||||
|
||||
def finalInit(self):
|
||||
def finalInit(self) -> None:
|
||||
# This function should be called once during startup, after
|
||||
# most things are imported.
|
||||
from direct.fsm.StatePush import StateVar
|
||||
|
|
@ -175,7 +189,7 @@ class TaskManager:
|
|||
self._profileFrames = StateVar(False)
|
||||
self.setProfileFrames(ConfigVariableBool('profile-frames', 0).getValue())
|
||||
|
||||
def destroy(self):
|
||||
def destroy(self) -> None:
|
||||
# This should be safe to call multiple times.
|
||||
self.running = False
|
||||
self.notify.info("TaskManager.destroy()")
|
||||
|
|
@ -183,11 +197,14 @@ class TaskManager:
|
|||
self._frameProfileQueue.clear()
|
||||
self.mgr.cleanup()
|
||||
|
||||
def setClock(self, clockObject):
|
||||
def __getClock(self) -> ClockObject:
|
||||
return self.mgr.getClock()
|
||||
|
||||
def setClock(self, clockObject: ClockObject) -> None:
|
||||
self.mgr.setClock(clockObject)
|
||||
self.globalClock = clockObject
|
||||
|
||||
clock = property(lambda self: self.mgr.getClock(), setClock)
|
||||
clock = property(__getClock, setClock)
|
||||
|
||||
def invokeDefaultHandler(self, signalNumber, stackFrame):
|
||||
print('*** allowing mid-frame keyboard interrupt.')
|
||||
|
|
@ -208,13 +225,13 @@ class TaskManager:
|
|||
# Next time around invoke the default handler
|
||||
signal.signal(signal.SIGINT, self.invokeDefaultHandler)
|
||||
|
||||
def getCurrentTask(self):
|
||||
def getCurrentTask(self) -> AsyncTask | None:
|
||||
""" Returns the task currently executing on this thread, or
|
||||
None if this is being called outside of the task manager. """
|
||||
|
||||
return Thread.getCurrentThread().getCurrentTask()
|
||||
|
||||
def hasTaskChain(self, chainName):
|
||||
def hasTaskChain(self, chainName: str) -> bool:
|
||||
""" Returns true if a task chain with the indicated name has
|
||||
already been defined, or false otherwise. Note that
|
||||
setupTaskChain() will implicitly define a task chain if it has
|
||||
|
|
@ -224,9 +241,16 @@ class TaskManager:
|
|||
|
||||
return self.mgr.findTaskChain(chainName) is not None
|
||||
|
||||
def setupTaskChain(self, chainName, numThreads = None, tickClock = None,
|
||||
threadPriority = None, frameBudget = None,
|
||||
frameSync = None, timeslicePriority = None):
|
||||
def setupTaskChain(
|
||||
self,
|
||||
chainName: str,
|
||||
numThreads: int | None = None,
|
||||
tickClock: bool | None = None,
|
||||
threadPriority: int | None = None,
|
||||
frameBudget: float | None = None,
|
||||
frameSync: bool | None = None,
|
||||
timeslicePriority: bool | None = None,
|
||||
) -> None:
|
||||
"""Defines a new task chain. Each task chain executes tasks
|
||||
potentially in parallel with all of the other task chains (if
|
||||
numThreads is more than zero). When a new task is created, it
|
||||
|
|
@ -290,40 +314,50 @@ class TaskManager:
|
|||
if timeslicePriority is not None:
|
||||
chain.setTimeslicePriority(timeslicePriority)
|
||||
|
||||
def hasTaskNamed(self, taskName):
|
||||
def hasTaskNamed(self, taskName: str) -> bool:
|
||||
"""Returns true if there is at least one task, active or
|
||||
sleeping, with the indicated name. """
|
||||
|
||||
return bool(self.mgr.findTask(taskName))
|
||||
|
||||
def getTasksNamed(self, taskName):
|
||||
def getTasksNamed(self, taskName: str) -> list[AsyncTask]:
|
||||
"""Returns a list of all tasks, active or sleeping, with the
|
||||
indicated name. """
|
||||
return list(self.mgr.findTasks(taskName))
|
||||
|
||||
def getTasksMatching(self, taskPattern):
|
||||
def getTasksMatching(self, taskPattern: GlobPattern | str) -> list[AsyncTask]:
|
||||
"""Returns a list of all tasks, active or sleeping, with a
|
||||
name that matches the pattern, which can include standard
|
||||
shell globbing characters like \\*, ?, and []. """
|
||||
|
||||
return list(self.mgr.findTasksMatching(GlobPattern(taskPattern)))
|
||||
|
||||
def getAllTasks(self):
|
||||
def getAllTasks(self) -> list[AsyncTask]:
|
||||
"""Returns list of all tasks, active and sleeping, in
|
||||
arbitrary order. """
|
||||
return list(self.mgr.getTasks())
|
||||
|
||||
def getTasks(self):
|
||||
def getTasks(self) -> list[AsyncTask]:
|
||||
"""Returns list of all active tasks in arbitrary order. """
|
||||
return list(self.mgr.getActiveTasks())
|
||||
|
||||
def getDoLaters(self):
|
||||
def getDoLaters(self) -> list[AsyncTask]:
|
||||
"""Returns list of all sleeping tasks in arbitrary order. """
|
||||
return list(self.mgr.getSleepingTasks())
|
||||
|
||||
def doMethodLater(self, delayTime, funcOrTask, name, extraArgs = None,
|
||||
sort = None, priority = None, taskChain = None,
|
||||
uponDeath = None, appendTask = False, owner = None):
|
||||
def doMethodLater(
|
||||
self,
|
||||
delayTime: float,
|
||||
funcOrTask: _FuncOrTask,
|
||||
name: str | None,
|
||||
extraArgs: Sequence | None = None,
|
||||
sort: int | None = None,
|
||||
priority: int | None = None,
|
||||
taskChain: str | None = None,
|
||||
uponDeath: Callable[[], object] | None = None,
|
||||
appendTask: bool = False,
|
||||
owner = None,
|
||||
) -> AsyncTask:
|
||||
"""Adds a task to be performed at some time in the future.
|
||||
This is identical to `add()`, except that the specified
|
||||
delayTime is applied to the Task object first, which means
|
||||
|
|
@ -346,9 +380,19 @@ class TaskManager:
|
|||
|
||||
do_method_later = doMethodLater
|
||||
|
||||
def add(self, funcOrTask, name = None, sort = None, extraArgs = None,
|
||||
priority = None, uponDeath = None, appendTask = False,
|
||||
taskChain = None, owner = None, delay = None):
|
||||
def add(
|
||||
self,
|
||||
funcOrTask: _FuncOrTask,
|
||||
name: str | None = None,
|
||||
sort: int | None = None,
|
||||
extraArgs: Sequence | None = None,
|
||||
priority: int | None = None,
|
||||
uponDeath: Callable[[], object] | None = None,
|
||||
appendTask: bool = False,
|
||||
taskChain: str | None = None,
|
||||
owner = None,
|
||||
delay: float | None = None,
|
||||
) -> AsyncTask:
|
||||
"""
|
||||
Add a new task to the taskMgr. The task will begin executing
|
||||
immediately, or next frame if its sort value has already
|
||||
|
|
@ -415,7 +459,18 @@ class TaskManager:
|
|||
self.mgr.add(task)
|
||||
return task
|
||||
|
||||
def __setupTask(self, funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath):
|
||||
def __setupTask(
|
||||
self,
|
||||
funcOrTask: _FuncOrTask,
|
||||
name: str | None,
|
||||
priority: int | None,
|
||||
sort: int | None,
|
||||
extraArgs: Sequence | None,
|
||||
taskChain: str | None,
|
||||
appendTask: bool,
|
||||
owner,
|
||||
uponDeath: Callable[[], object] | None,
|
||||
) -> AsyncTask:
|
||||
wasTask = False
|
||||
if isinstance(funcOrTask, AsyncTask):
|
||||
task = funcOrTask
|
||||
|
|
@ -473,7 +528,7 @@ class TaskManager:
|
|||
|
||||
return task
|
||||
|
||||
def remove(self, taskOrName):
|
||||
def remove(self, taskOrName: AsyncTask | str | list[AsyncTask | str]) -> int:
|
||||
"""Removes a task from the task manager. The task is stopped,
|
||||
almost as if it had returned task.done. (But if the task is
|
||||
currently executing, it will finish out its current frame
|
||||
|
|
@ -485,13 +540,15 @@ class TaskManager:
|
|||
if isinstance(taskOrName, AsyncTask):
|
||||
return self.mgr.remove(taskOrName)
|
||||
elif isinstance(taskOrName, list):
|
||||
count = 0
|
||||
for task in taskOrName:
|
||||
self.remove(task)
|
||||
count += self.remove(task)
|
||||
return count
|
||||
else:
|
||||
tasks = self.mgr.findTasks(taskOrName)
|
||||
return self.mgr.remove(tasks)
|
||||
|
||||
def removeTasksMatching(self, taskPattern):
|
||||
def removeTasksMatching(self, taskPattern: GlobPattern | str) -> int:
|
||||
"""Removes all tasks whose names match the pattern, which can
|
||||
include standard shell globbing characters like \\*, ?, and [].
|
||||
See also :meth:`remove()`.
|
||||
|
|
@ -501,7 +558,7 @@ class TaskManager:
|
|||
tasks = self.mgr.findTasksMatching(GlobPattern(taskPattern))
|
||||
return self.mgr.remove(tasks)
|
||||
|
||||
def step(self):
|
||||
def step(self) -> None:
|
||||
"""Invokes the task manager for one frame, and then returns.
|
||||
Normally, this executes each task exactly once, though task
|
||||
chains that are in sub-threads or that have frame budgets
|
||||
|
|
@ -512,7 +569,7 @@ class TaskManager:
|
|||
# Replace keyboard interrupt handler during task list processing
|
||||
# so we catch the keyboard interrupt but don't handle it until
|
||||
# after task list processing is complete.
|
||||
self.fKeyboardInterrupt = 0
|
||||
self.fKeyboardInterrupt = False
|
||||
self.interruptCount = 0
|
||||
|
||||
if signal:
|
||||
|
|
@ -534,7 +591,7 @@ class TaskManager:
|
|||
if self.fKeyboardInterrupt:
|
||||
raise KeyboardInterrupt
|
||||
|
||||
def run(self):
|
||||
def run(self) -> None:
|
||||
"""Starts the task manager running. Does not return until an
|
||||
exception is encountered (including KeyboardInterrupt). """
|
||||
|
||||
|
|
@ -560,11 +617,11 @@ class TaskManager:
|
|||
if len(self._frameProfileQueue) > 0:
|
||||
numFrames, session, callback = self._frameProfileQueue.pop(0)
|
||||
|
||||
def _profileFunc(numFrames=numFrames):
|
||||
def _profileFunc(numFrames: int = numFrames) -> None:
|
||||
self._doProfiledFrames(numFrames)
|
||||
session.setFunc(_profileFunc)
|
||||
session.run()
|
||||
_profileFunc = None
|
||||
del _profileFunc
|
||||
if callback:
|
||||
callback()
|
||||
session.release()
|
||||
|
|
@ -617,7 +674,7 @@ class TaskManager:
|
|||
message = ioError
|
||||
return code, message
|
||||
|
||||
def stop(self):
|
||||
def stop(self) -> None:
|
||||
# Set a flag so we will stop before beginning next frame
|
||||
self.running = False
|
||||
|
||||
|
|
@ -782,12 +839,12 @@ class TaskManager:
|
|||
task = tasks.getTask(i)
|
||||
return task
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return str(self.mgr)
|
||||
|
||||
# In the event we want to do frame time managment, this is the
|
||||
# function to replace or overload.
|
||||
def doYield(self, frameStartTime, nextScheduledTaskTime):
|
||||
def doYield(self, frameStartTime: float, nextScheduledTaskTime: float) -> None:
|
||||
pass
|
||||
|
||||
#def doYieldExample(self, frameStartTime, nextScheduledTaskTime):
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ from direct.tkwidgets import VectorWidgets
|
|||
from direct.tkwidgets import SceneGraphExplorer
|
||||
from direct.tkwidgets import MemoryExplorer
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
from .TaskManagerPanel import TaskManagerWidget
|
||||
import Pmw
|
||||
import tkinter as tk
|
||||
|
|
@ -44,8 +45,8 @@ class DirectSessionPanel(AppShell):
|
|||
AppShell.__init__(self, parent)
|
||||
|
||||
# Active light
|
||||
if len(base.direct.lights) > 0:
|
||||
name = base.direct.lights.getNameList()[0]
|
||||
if len(ShowBaseGlobal.direct.lights) > 0:
|
||||
name = ShowBaseGlobal.direct.lights.getNameList()[0]
|
||||
self.lightMenu.selectitem(name)
|
||||
self.selectLightNamed(name)
|
||||
else:
|
||||
|
|
@ -62,14 +63,14 @@ class DirectSessionPanel(AppShell):
|
|||
# Initialize state
|
||||
# Dictionary keeping track of all node paths selected so far
|
||||
self.nodePathDict = {}
|
||||
self.nodePathDict['widget'] = base.direct.widget
|
||||
self.nodePathDict['widget'] = ShowBaseGlobal.direct.widget
|
||||
self.nodePathNames = ['widget']
|
||||
|
||||
# Dictionary keeping track of all jb node paths selected so far
|
||||
self.jbNodePathDict = {}
|
||||
self.jbNodePathDict['none'] = 'No Node Path'
|
||||
self.jbNodePathDict['widget'] = base.direct.widget
|
||||
self.jbNodePathDict['camera'] = base.direct.camera
|
||||
self.jbNodePathDict['widget'] = ShowBaseGlobal.direct.widget
|
||||
self.jbNodePathDict['camera'] = ShowBaseGlobal.direct.camera
|
||||
self.jbNodePathNames = ['camera', 'selected', 'none']
|
||||
|
||||
# Set up event hooks
|
||||
|
|
@ -93,7 +94,7 @@ class DirectSessionPanel(AppShell):
|
|||
self.menuBar.addmenu('DIRECT', 'Direct Session Panel Operations')
|
||||
|
||||
self.directEnabled = tk.BooleanVar()
|
||||
self.directEnabled.set(1)
|
||||
self.directEnabled.set(True)
|
||||
self.menuBar.addmenuitem('DIRECT', 'checkbutton',
|
||||
'DIRECT Enabled',
|
||||
label = 'Enable',
|
||||
|
|
@ -101,7 +102,7 @@ class DirectSessionPanel(AppShell):
|
|||
command = self.toggleDirect)
|
||||
|
||||
self.directGridEnabled = tk.BooleanVar()
|
||||
self.directGridEnabled.set(base.direct.grid.isEnabled())
|
||||
self.directGridEnabled.set(ShowBaseGlobal.direct.grid.isEnabled())
|
||||
self.menuBar.addmenuitem('DIRECT', 'checkbutton',
|
||||
'DIRECT Grid Enabled',
|
||||
label = 'Enable Grid',
|
||||
|
|
@ -111,16 +112,16 @@ class DirectSessionPanel(AppShell):
|
|||
self.menuBar.addmenuitem('DIRECT', 'command',
|
||||
'Toggle Object Handles Visability',
|
||||
label = 'Toggle Widget Viz',
|
||||
command = base.direct.toggleWidgetVis)
|
||||
command = ShowBaseGlobal.direct.toggleWidgetVis)
|
||||
|
||||
self.menuBar.addmenuitem(
|
||||
'DIRECT', 'command',
|
||||
'Toggle Widget Move/COA Mode',
|
||||
label = 'Toggle Widget Mode',
|
||||
command = base.direct.manipulationControl.toggleObjectHandlesMode)
|
||||
command = ShowBaseGlobal.direct.manipulationControl.toggleObjectHandlesMode)
|
||||
|
||||
self.directWidgetOnTop = tk.BooleanVar()
|
||||
self.directWidgetOnTop.set(0)
|
||||
self.directWidgetOnTop.set(False)
|
||||
self.menuBar.addmenuitem('DIRECT', 'checkbutton',
|
||||
'DIRECT Widget On Top',
|
||||
label = 'Widget On Top',
|
||||
|
|
@ -130,7 +131,7 @@ class DirectSessionPanel(AppShell):
|
|||
self.menuBar.addmenuitem('DIRECT', 'command',
|
||||
'Deselect All',
|
||||
label = 'Deselect All',
|
||||
command = base.direct.deselectAll)
|
||||
command = ShowBaseGlobal.direct.deselectAll)
|
||||
|
||||
# Get a handle to the menu frame
|
||||
menuFrame = self.menuFrame
|
||||
|
|
@ -150,8 +151,8 @@ class DirectSessionPanel(AppShell):
|
|||
self.bind(self.nodePathMenu, 'Select node path to manipulate')
|
||||
|
||||
self.undoButton = tk.Button(menuFrame, text = 'Undo',
|
||||
command = base.direct.undo)
|
||||
if base.direct.undoList:
|
||||
command = ShowBaseGlobal.direct.undo)
|
||||
if ShowBaseGlobal.direct.undoList:
|
||||
self.undoButton['state'] = 'normal'
|
||||
else:
|
||||
self.undoButton['state'] = 'disabled'
|
||||
|
|
@ -159,8 +160,8 @@ class DirectSessionPanel(AppShell):
|
|||
self.bind(self.undoButton, 'Undo last operation')
|
||||
|
||||
self.redoButton = tk.Button(menuFrame, text = 'Redo',
|
||||
command = base.direct.redo)
|
||||
if base.direct.redoList:
|
||||
command = ShowBaseGlobal.direct.redo)
|
||||
if ShowBaseGlobal.direct.redoList:
|
||||
self.redoButton['state'] = 'normal'
|
||||
else:
|
||||
self.redoButton['state'] = 'disabled'
|
||||
|
|
@ -177,7 +178,7 @@ class DirectSessionPanel(AppShell):
|
|||
|
||||
# Scene Graph Explorer
|
||||
self.SGE = SceneGraphExplorer.SceneGraphExplorer(
|
||||
sgeFrame, nodePath = render,
|
||||
sgeFrame, nodePath = ShowBaseGlobal.base.render,
|
||||
scrolledCanvas_hull_width = 250,
|
||||
scrolledCanvas_hull_height = 300)
|
||||
self.SGE.pack(fill = tk.BOTH, expand = 1)
|
||||
|
|
@ -218,7 +219,7 @@ class DirectSessionPanel(AppShell):
|
|||
tk.Label(drFrame, text = 'Display Region',
|
||||
font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
|
||||
|
||||
nameList = ['Display Region ' + repr(x) for x in range(len(base.direct.drList))]
|
||||
nameList = ['Display Region ' + repr(x) for x in range(len(ShowBaseGlobal.direct.drList))]
|
||||
self.drMenu = Pmw.ComboBox(
|
||||
drFrame, labelpos = tk.W, label_text = 'Display Region:',
|
||||
entry_width = 20,
|
||||
|
|
@ -264,7 +265,7 @@ class DirectSessionPanel(AppShell):
|
|||
|
||||
frame = tk.Frame(fovFrame)
|
||||
self.lockedFov = tk.BooleanVar()
|
||||
self.lockedFov.set(1)
|
||||
self.lockedFov.set(True)
|
||||
self.lockedFovButton = tk.Checkbutton(
|
||||
frame,
|
||||
text = 'Locked',
|
||||
|
|
@ -289,25 +290,25 @@ class DirectSessionPanel(AppShell):
|
|||
self.toggleBackfaceButton = tk.Button(
|
||||
toggleFrame,
|
||||
text = 'Backface',
|
||||
command = base.toggleBackface)
|
||||
command = ShowBaseGlobal.base.toggleBackface)
|
||||
self.toggleBackfaceButton.pack(side = tk.LEFT, fill = tk.X, expand = 1)
|
||||
|
||||
self.toggleLightsButton = tk.Button(
|
||||
toggleFrame,
|
||||
text = 'Lights',
|
||||
command = base.direct.lights.toggle)
|
||||
command = ShowBaseGlobal.direct.lights.toggle)
|
||||
self.toggleLightsButton.pack(side = tk.LEFT, fill = tk.X, expand = 1)
|
||||
|
||||
self.toggleTextureButton = tk.Button(
|
||||
toggleFrame,
|
||||
text = 'Texture',
|
||||
command = base.toggleTexture)
|
||||
command = ShowBaseGlobal.base.toggleTexture)
|
||||
self.toggleTextureButton.pack(side = tk.LEFT, fill = tk.X, expand = 1)
|
||||
|
||||
self.toggleWireframeButton = tk.Button(
|
||||
toggleFrame,
|
||||
text = 'Wireframe',
|
||||
command = base.toggleWireframe)
|
||||
command = ShowBaseGlobal.base.toggleWireframe)
|
||||
self.toggleWireframeButton.pack(fill = tk.X, expand = 1)
|
||||
toggleFrame.pack(side = tk.LEFT, fill = tk.X, expand = 1)
|
||||
|
||||
|
|
@ -354,7 +355,7 @@ class DirectSessionPanel(AppShell):
|
|||
mainSwitchFrame.pack(fill = tk.X, expand = 0)
|
||||
|
||||
# Widget to select a light to configure
|
||||
nameList = base.direct.lights.getNameList()
|
||||
nameList = ShowBaseGlobal.direct.lights.getNameList()
|
||||
lightMenuFrame = tk.Frame(lightFrame)
|
||||
|
||||
self.lightMenu = Pmw.ComboBox(
|
||||
|
|
@ -510,36 +511,36 @@ class DirectSessionPanel(AppShell):
|
|||
gridPage,
|
||||
text = 'Grid Spacing',
|
||||
min = 0.1,
|
||||
value = base.direct.grid.getGridSpacing())
|
||||
self.gridSpacing['command'] = base.direct.grid.setGridSpacing
|
||||
value = ShowBaseGlobal.direct.grid.getGridSpacing())
|
||||
self.gridSpacing['command'] = ShowBaseGlobal.direct.grid.setGridSpacing
|
||||
self.gridSpacing.pack(fill = tk.X, expand = 0)
|
||||
|
||||
self.gridSize = Floater.Floater(
|
||||
gridPage,
|
||||
text = 'Grid Size',
|
||||
min = 1.0,
|
||||
value = base.direct.grid.getGridSize())
|
||||
self.gridSize['command'] = base.direct.grid.setGridSize
|
||||
value = ShowBaseGlobal.direct.grid.getGridSize())
|
||||
self.gridSize['command'] = ShowBaseGlobal.direct.grid.setGridSize
|
||||
self.gridSize.pack(fill = tk.X, expand = 0)
|
||||
|
||||
self.gridSnapAngle = Dial.AngleDial(
|
||||
gridPage,
|
||||
text = 'Snap Angle',
|
||||
style = 'mini',
|
||||
value = base.direct.grid.getSnapAngle())
|
||||
self.gridSnapAngle['command'] = base.direct.grid.setSnapAngle
|
||||
value = ShowBaseGlobal.direct.grid.getSnapAngle())
|
||||
self.gridSnapAngle['command'] = ShowBaseGlobal.direct.grid.setSnapAngle
|
||||
self.gridSnapAngle.pack(fill = tk.X, expand = 0)
|
||||
|
||||
def createDevicePage(self, devicePage):
|
||||
tk.Label(devicePage, text = 'DEVICES',
|
||||
font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
|
||||
|
||||
if base.direct.joybox is not None:
|
||||
if ShowBaseGlobal.direct.joybox is not None:
|
||||
joyboxFrame = tk.Frame(devicePage, borderwidth = 2, relief = 'sunken')
|
||||
tk.Label(joyboxFrame, text = 'Joybox',
|
||||
font=('MSSansSerif', 14, 'bold')).pack(expand = 0)
|
||||
self.enableJoybox = tk.BooleanVar()
|
||||
self.enableJoybox.set(1)
|
||||
self.enableJoybox.set(True)
|
||||
self.enableJoyboxButton = tk.Checkbutton(
|
||||
joyboxFrame,
|
||||
text = 'Enabled/Disabled',
|
||||
|
|
@ -581,7 +582,7 @@ class DirectSessionPanel(AppShell):
|
|||
hull_relief = tk.RIDGE, hull_borderwidth = 2,
|
||||
min = 1.0, max = 100.0)
|
||||
self.jbXyzSF['command'] = (
|
||||
lambda v: base.direct.joybox.setXyzMultiplier(v))
|
||||
lambda v: ShowBaseGlobal.direct.joybox.setXyzMultiplier(v))
|
||||
self.jbXyzSF.pack(fill = tk.X, expand = 0)
|
||||
self.bind(self.jbXyzSF, 'Set joybox XYZ speed multiplier')
|
||||
|
||||
|
|
@ -592,7 +593,7 @@ class DirectSessionPanel(AppShell):
|
|||
hull_relief = tk.RIDGE, hull_borderwidth = 2,
|
||||
min = 1.0, max = 100.0)
|
||||
self.jbHprSF['command'] = (
|
||||
lambda v: base.direct.joybox.setHprMultiplier(v))
|
||||
lambda v: ShowBaseGlobal.direct.joybox.setHprMultiplier(v))
|
||||
self.jbHprSF.pack(fill = tk.X, expand = 0)
|
||||
self.bind(self.jbHprSF, 'Set joybox HPR speed multiplier')
|
||||
|
||||
|
|
@ -604,30 +605,30 @@ class DirectSessionPanel(AppShell):
|
|||
|
||||
def createMemPage(self, memPage):
|
||||
self.MemExp = MemoryExplorer.MemoryExplorer(
|
||||
memPage, nodePath = render,
|
||||
memPage, nodePath = ShowBaseGlobal.base.render,
|
||||
scrolledCanvas_hull_width = 250,
|
||||
scrolledCanvas_hull_height = 250)
|
||||
self.MemExp.pack(fill = tk.BOTH, expand = 1)
|
||||
|
||||
def toggleDirect(self):
|
||||
if self.directEnabled.get():
|
||||
base.direct.enable()
|
||||
ShowBaseGlobal.direct.enable()
|
||||
else:
|
||||
base.direct.disable()
|
||||
ShowBaseGlobal.direct.disable()
|
||||
|
||||
def toggleDirectGrid(self):
|
||||
if self.directGridEnabled.get():
|
||||
base.direct.grid.enable()
|
||||
ShowBaseGlobal.direct.grid.enable()
|
||||
else:
|
||||
base.direct.grid.disable()
|
||||
ShowBaseGlobal.direct.grid.disable()
|
||||
|
||||
def toggleWidgetOnTop(self):
|
||||
if self.directWidgetOnTop.get():
|
||||
base.direct.widget.setBin('gui-popup', 0)
|
||||
base.direct.widget.setDepthTest(0)
|
||||
ShowBaseGlobal.direct.widget.setBin('gui-popup', 0)
|
||||
ShowBaseGlobal.direct.widget.setDepthTest(0)
|
||||
else:
|
||||
base.direct.widget.clearBin()
|
||||
base.direct.widget.setDepthTest(1)
|
||||
ShowBaseGlobal.direct.widget.clearBin()
|
||||
ShowBaseGlobal.direct.widget.setDepthTest(1)
|
||||
|
||||
def selectedNodePathHook(self, nodePath):
|
||||
# Make sure node path is in nodePathDict
|
||||
|
|
@ -657,7 +658,7 @@ class DirectSessionPanel(AppShell):
|
|||
# Did we finally get something?
|
||||
if nodePath is not None:
|
||||
# Yes, select it!
|
||||
base.direct.select(nodePath)
|
||||
ShowBaseGlobal.direct.select(nodePath)
|
||||
|
||||
def addNodePath(self, nodePath):
|
||||
self.addNodePathToDict(nodePath, self.nodePathNames,
|
||||
|
|
@ -665,25 +666,25 @@ class DirectSessionPanel(AppShell):
|
|||
|
||||
def selectJBModeNamed(self, name):
|
||||
if name == 'Joe Mode':
|
||||
base.direct.joybox.joeMode()
|
||||
ShowBaseGlobal.direct.joybox.joeMode()
|
||||
elif name == 'Drive Mode':
|
||||
base.direct.joybox.driveMode()
|
||||
ShowBaseGlobal.direct.joybox.driveMode()
|
||||
elif name == 'Orbit Mode':
|
||||
base.direct.joybox.orbitMode()
|
||||
ShowBaseGlobal.direct.joybox.orbitMode()
|
||||
elif name == 'Look At Mode':
|
||||
base.direct.joybox.lookAtMode()
|
||||
ShowBaseGlobal.direct.joybox.lookAtMode()
|
||||
elif name == 'Look Around Mode':
|
||||
base.direct.joybox.lookAroundMode()
|
||||
ShowBaseGlobal.direct.joybox.lookAroundMode()
|
||||
elif name == 'Walkthru Mode':
|
||||
base.direct.joybox.walkthruMode()
|
||||
ShowBaseGlobal.direct.joybox.walkthruMode()
|
||||
elif name == 'Demo Mode':
|
||||
base.direct.joybox.demoMode()
|
||||
ShowBaseGlobal.direct.joybox.demoMode()
|
||||
elif name == 'HPRXYZ Mode':
|
||||
base.direct.joybox.hprXyzMode()
|
||||
ShowBaseGlobal.direct.joybox.hprXyzMode()
|
||||
|
||||
def selectJBNodePathNamed(self, name):
|
||||
if name == 'selected':
|
||||
nodePath = base.direct.selected.last
|
||||
nodePath = ShowBaseGlobal.direct.selected.last
|
||||
# Add Combo box entry for this selected object
|
||||
self.addJBNodePath(nodePath)
|
||||
else:
|
||||
|
|
@ -708,9 +709,9 @@ class DirectSessionPanel(AppShell):
|
|||
if nodePath is not None:
|
||||
# Yes, select it!
|
||||
if nodePath == 'No Node Path':
|
||||
base.direct.joybox.setNodePath(None)
|
||||
ShowBaseGlobal.direct.joybox.setNodePath(None)
|
||||
else:
|
||||
base.direct.joybox.setNodePath(nodePath)
|
||||
ShowBaseGlobal.direct.joybox.setNodePath(nodePath)
|
||||
|
||||
def addJBNodePath(self, nodePath):
|
||||
self.addNodePathToDict(nodePath, self.jbNodePathNames,
|
||||
|
|
@ -741,14 +742,13 @@ class DirectSessionPanel(AppShell):
|
|||
self.setBackgroundColorVec((r, g, b))
|
||||
|
||||
def setBackgroundColorVec(self, color):
|
||||
base.setBackgroundColor(color[0]/255.0,
|
||||
color[1]/255.0,
|
||||
color[2]/255.0)
|
||||
ShowBaseGlobal.base.setBackgroundColor(
|
||||
color[0] / 255.0, color[1] / 255.0, color[2] / 255.0)
|
||||
|
||||
def selectDisplayRegionNamed(self, name):
|
||||
if name.find('Display Region ') >= 0:
|
||||
drIndex = int(name[-1:])
|
||||
self.activeDisplayRegion = base.direct.drList[drIndex]
|
||||
self.activeDisplayRegion = ShowBaseGlobal.direct.drList[drIndex]
|
||||
else:
|
||||
self.activeDisplayRegion = None
|
||||
# Make sure info is current
|
||||
|
|
@ -758,13 +758,13 @@ class DirectSessionPanel(AppShell):
|
|||
dr = self.activeDisplayRegion
|
||||
if dr:
|
||||
dr.camLens.setNear(near)
|
||||
cluster('base.camLens.setNear(%f)' % near, 0)
|
||||
ShowBaseGlobal.direct.cluster('base.camLens.setNear(%f)' % near, 0)
|
||||
|
||||
def setFar(self, far):
|
||||
dr = self.activeDisplayRegion
|
||||
if dr:
|
||||
dr.camLens.setFar(far)
|
||||
cluster('base.camLens.setFar(%f)' % far, 0)
|
||||
ShowBaseGlobal.direct.cluster('base.camLens.setFar(%f)' % far, 0)
|
||||
|
||||
def setHFov(self, hFov):
|
||||
dr = self.activeDisplayRegion
|
||||
|
|
@ -802,10 +802,10 @@ class DirectSessionPanel(AppShell):
|
|||
# Lights #
|
||||
def selectLightNamed(self, name):
|
||||
# See if light exists
|
||||
self.activeLight = base.direct.lights[name]
|
||||
self.activeLight = ShowBaseGlobal.direct.lights[name]
|
||||
# If not...create new one
|
||||
if self.activeLight is None:
|
||||
self.activeLight = base.direct.lights.create(name)
|
||||
self.activeLight = ShowBaseGlobal.direct.lights.create(name)
|
||||
# Do we have a valid light at this point?
|
||||
if self.activeLight:
|
||||
light = self.activeLight.getLight()
|
||||
|
|
@ -820,28 +820,28 @@ class DirectSessionPanel(AppShell):
|
|||
else:
|
||||
# Restore valid data
|
||||
listbox = self.lightMenu.component('scrolledlist')
|
||||
listbox.setlist(base.direct.lights.getNameList())
|
||||
if len(base.direct.lights) > 0:
|
||||
self.lightMenu.selectitem(base.direct.lights.getNameList()[0])
|
||||
listbox.setlist(ShowBaseGlobal.direct.lights.getNameList())
|
||||
if len(ShowBaseGlobal.direct.lights) > 0:
|
||||
self.lightMenu.selectitem(ShowBaseGlobal.direct.lights.getNameList()[0])
|
||||
# Make sure info is current
|
||||
self.updateLightInfo()
|
||||
|
||||
def addAmbient(self):
|
||||
return base.direct.lights.create('ambient')
|
||||
return ShowBaseGlobal.direct.lights.create('ambient')
|
||||
|
||||
def addDirectional(self):
|
||||
return base.direct.lights.create('directional')
|
||||
return ShowBaseGlobal.direct.lights.create('directional')
|
||||
|
||||
def addPoint(self):
|
||||
return base.direct.lights.create('point')
|
||||
return ShowBaseGlobal.direct.lights.create('point')
|
||||
|
||||
def addSpot(self):
|
||||
return base.direct.lights.create('spot')
|
||||
return ShowBaseGlobal.direct.lights.create('spot')
|
||||
|
||||
def addLight(self, light):
|
||||
# Make list reflect current list of lights
|
||||
listbox = self.lightMenu.component('scrolledlist')
|
||||
listbox.setlist(base.direct.lights.getNameList())
|
||||
listbox.setlist(ShowBaseGlobal.direct.lights.getNameList())
|
||||
# Select the newly added light
|
||||
self.lightMenu.selectitem(light.getName())
|
||||
# And show corresponding page
|
||||
|
|
@ -849,16 +849,16 @@ class DirectSessionPanel(AppShell):
|
|||
|
||||
def toggleLights(self):
|
||||
if self.enableLights.get():
|
||||
base.direct.lights.allOn()
|
||||
ShowBaseGlobal.direct.lights.allOn()
|
||||
else:
|
||||
base.direct.lights.allOff()
|
||||
ShowBaseGlobal.direct.lights.allOff()
|
||||
|
||||
def toggleActiveLight(self):
|
||||
if self.activeLight:
|
||||
if self.lightActive.get():
|
||||
base.direct.lights.setOn(self.activeLight)
|
||||
ShowBaseGlobal.direct.lights.setOn(self.activeLight)
|
||||
else:
|
||||
base.direct.lights.setOff(self.activeLight)
|
||||
ShowBaseGlobal.direct.lights.setOff(self.activeLight)
|
||||
|
||||
def setLightColor(self, color):
|
||||
if self.activeLight:
|
||||
|
|
@ -893,22 +893,22 @@ class DirectSessionPanel(AppShell):
|
|||
## GRID CONTROLS ##
|
||||
def toggleGrid(self):
|
||||
if self.enableGrid.get():
|
||||
base.direct.grid.enable()
|
||||
ShowBaseGlobal.direct.grid.enable()
|
||||
else:
|
||||
base.direct.grid.disable()
|
||||
ShowBaseGlobal.direct.grid.disable()
|
||||
|
||||
def toggleXyzSnap(self):
|
||||
base.direct.grid.setXyzSnap(self.xyzSnap.get())
|
||||
ShowBaseGlobal.direct.grid.setXyzSnap(self.xyzSnap.get())
|
||||
|
||||
def toggleHprSnap(self):
|
||||
base.direct.grid.setHprSnap(self.hprSnap.get())
|
||||
ShowBaseGlobal.direct.grid.setHprSnap(self.hprSnap.get())
|
||||
|
||||
## DEVICE CONTROLS
|
||||
def toggleJoybox(self):
|
||||
if self.enableJoybox.get():
|
||||
base.direct.joybox.enable()
|
||||
ShowBaseGlobal.direct.joybox.enable()
|
||||
else:
|
||||
base.direct.joybox.disable()
|
||||
ShowBaseGlobal.direct.joybox.disable()
|
||||
|
||||
## UPDATE INFO ##
|
||||
def updateInfo(self, page = 'Environment'):
|
||||
|
|
@ -920,7 +920,7 @@ class DirectSessionPanel(AppShell):
|
|||
self.updateGridInfo()
|
||||
|
||||
def updateEnvironmentInfo(self):
|
||||
bkgrdColor = base.getBackgroundColor() * 255.0
|
||||
bkgrdColor = ShowBaseGlobal.base.getBackgroundColor() * 255.0
|
||||
self.backgroundColor.set([bkgrdColor[0],
|
||||
bkgrdColor[1],
|
||||
bkgrdColor[2],
|
||||
|
|
@ -936,6 +936,7 @@ class DirectSessionPanel(AppShell):
|
|||
|
||||
def updateLightInfo(self, page = None):
|
||||
# Set main lighting button
|
||||
render = ShowBaseGlobal.base.render
|
||||
self.enableLights.set(
|
||||
render.node().hasAttrib(LightAttrib.getClassType()))
|
||||
|
||||
|
|
@ -974,16 +975,16 @@ class DirectSessionPanel(AppShell):
|
|||
self.pQuadraticAttenuation.set(att[2], 0)
|
||||
|
||||
def updateGridInfo(self):
|
||||
self.enableGrid.set(base.direct.grid.isEnabled())
|
||||
self.xyzSnap.set(base.direct.grid.getXyzSnap())
|
||||
self.hprSnap.set(base.direct.grid.getHprSnap())
|
||||
self.gridSpacing.set(base.direct.grid.getGridSpacing(), 0)
|
||||
self.gridSize.set(base.direct.grid.getGridSize(), 0)
|
||||
self.gridSnapAngle.set(base.direct.grid.getSnapAngle(), 0)
|
||||
self.enableGrid.set(ShowBaseGlobal.direct.grid.isEnabled())
|
||||
self.xyzSnap.set(ShowBaseGlobal.direct.grid.getXyzSnap())
|
||||
self.hprSnap.set(ShowBaseGlobal.direct.grid.getHprSnap())
|
||||
self.gridSpacing.set(ShowBaseGlobal.direct.grid.getGridSpacing(), 0)
|
||||
self.gridSize.set(ShowBaseGlobal.direct.grid.getGridSize(), 0)
|
||||
self.gridSnapAngle.set(ShowBaseGlobal.direct.grid.getSnapAngle(), 0)
|
||||
|
||||
# UNDO/REDO
|
||||
def pushUndo(self, fResetRedo = 1):
|
||||
base.direct.pushUndo([self['nodePath']])
|
||||
ShowBaseGlobal.direct.pushUndo([self['nodePath']])
|
||||
|
||||
def undoHook(self, nodePathList = []):
|
||||
pass
|
||||
|
|
@ -997,7 +998,7 @@ class DirectSessionPanel(AppShell):
|
|||
self.undoButton.configure(state = 'disabled')
|
||||
|
||||
def pushRedo(self):
|
||||
base.direct.pushRedo([self['nodePath']])
|
||||
ShowBaseGlobal.direct.pushRedo([self['nodePath']])
|
||||
|
||||
def redoHook(self, nodePathList = []):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ def inspect(anObject):
|
|||
|
||||
### private
|
||||
|
||||
_InspectorMap: "dict[str, str]"
|
||||
|
||||
|
||||
def inspectorFor(anObject):
|
||||
typeName = type(anObject).__name__.capitalize() + 'Type'
|
||||
|
|
@ -396,7 +398,8 @@ class InspectorWindow:
|
|||
self.listWidget.component('listbox').focus_set()
|
||||
|
||||
def showHelp(self):
|
||||
help = tk.Toplevel(base.tkRoot)
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
help = tk.Toplevel(ShowBaseGlobal.base.tkRoot)
|
||||
help.title("Inspector Help")
|
||||
frame = tk.Frame(help)
|
||||
frame.pack()
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from direct.tkwidgets import Dial
|
|||
from direct.tkwidgets import Floater
|
||||
from direct.directtools.DirectGlobals import ZERO_VEC, UNIT_VEC
|
||||
from direct.showbase.MessengerGlobal import messenger
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
import Pmw
|
||||
import tkinter as tk
|
||||
|
|
@ -28,7 +29,7 @@ class Placer(AppShell):
|
|||
INITOPT = Pmw.INITOPT
|
||||
optiondefs = (
|
||||
('title', self.appname, None),
|
||||
('nodePath', base.direct.camera, None),
|
||||
('nodePath', ShowBaseGlobal.direct.camera, None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
|
|
@ -39,23 +40,23 @@ class Placer(AppShell):
|
|||
|
||||
def appInit(self):
|
||||
# Initialize state
|
||||
self.tempCS = base.direct.group.attachNewNode('placerTempCS')
|
||||
self.orbitFromCS = base.direct.group.attachNewNode(
|
||||
self.tempCS = ShowBaseGlobal.direct.group.attachNewNode('placerTempCS')
|
||||
self.orbitFromCS = ShowBaseGlobal.direct.group.attachNewNode(
|
||||
'placerOrbitFromCS')
|
||||
self.orbitToCS = base.direct.group.attachNewNode('placerOrbitToCS')
|
||||
self.orbitToCS = ShowBaseGlobal.direct.group.attachNewNode('placerOrbitToCS')
|
||||
self.refCS = self.tempCS
|
||||
|
||||
# Dictionary keeping track of all node paths manipulated so far
|
||||
self.nodePathDict = {}
|
||||
self.nodePathDict['camera'] = base.direct.camera
|
||||
self.nodePathDict['widget'] = base.direct.widget
|
||||
self.nodePathDict['camera'] = ShowBaseGlobal.direct.camera
|
||||
self.nodePathDict['widget'] = ShowBaseGlobal.direct.widget
|
||||
self.nodePathNames = ['camera', 'widget', 'selected']
|
||||
|
||||
self.refNodePathDict = {}
|
||||
self.refNodePathDict['parent'] = self['nodePath'].getParent()
|
||||
self.refNodePathDict['render'] = render
|
||||
self.refNodePathDict['camera'] = base.direct.camera
|
||||
self.refNodePathDict['widget'] = base.direct.widget
|
||||
self.refNodePathDict['camera'] = ShowBaseGlobal.direct.camera
|
||||
self.refNodePathDict['widget'] = ShowBaseGlobal.direct.widget
|
||||
self.refNodePathNames = ['parent', 'self', 'render',
|
||||
'camera', 'widget', 'selected']
|
||||
|
||||
|
|
@ -103,12 +104,12 @@ class Placer(AppShell):
|
|||
'Placer', 'command',
|
||||
'Toggle widget visability',
|
||||
label = 'Toggle Widget Vis',
|
||||
command = base.direct.toggleWidgetVis)
|
||||
command = ShowBaseGlobal.direct.toggleWidgetVis)
|
||||
self.menuBar.addmenuitem(
|
||||
'Placer', 'command',
|
||||
'Toggle widget manipulation mode',
|
||||
label = 'Toggle Widget Mode',
|
||||
command = base.direct.manipulationControl.toggleObjectHandlesMode)
|
||||
command = ShowBaseGlobal.direct.manipulationControl.toggleObjectHandlesMode)
|
||||
|
||||
# Get a handle to the menu frame
|
||||
menuFrame = self.menuFrame
|
||||
|
|
@ -145,8 +146,8 @@ class Placer(AppShell):
|
|||
self.bind(self.refNodePathMenu, 'Select relative node path')
|
||||
|
||||
self.undoButton = tk.Button(menuFrame, text = 'Undo',
|
||||
command = base.direct.undo)
|
||||
if base.direct.undoList:
|
||||
command = ShowBaseGlobal.direct.undo)
|
||||
if ShowBaseGlobal.direct.undoList:
|
||||
self.undoButton['state'] = 'normal'
|
||||
else:
|
||||
self.undoButton['state'] = 'disabled'
|
||||
|
|
@ -154,8 +155,8 @@ class Placer(AppShell):
|
|||
self.bind(self.undoButton, 'Undo last operation')
|
||||
|
||||
self.redoButton = tk.Button(menuFrame, text = 'Redo',
|
||||
command = base.direct.redo)
|
||||
if base.direct.redoList:
|
||||
command = ShowBaseGlobal.direct.redo)
|
||||
if ShowBaseGlobal.direct.redoList:
|
||||
self.redoButton['state'] = 'normal'
|
||||
else:
|
||||
self.redoButton['state'] = 'disabled'
|
||||
|
|
@ -394,7 +395,7 @@ class Placer(AppShell):
|
|||
# Add Combo box entry for the initial node path
|
||||
self.addNodePath(nodePath)
|
||||
elif name == 'selected':
|
||||
nodePath = base.direct.selected.last
|
||||
nodePath = ShowBaseGlobal.direct.selected.last
|
||||
# Add Combo box entry for this selected object
|
||||
self.addNodePath(nodePath)
|
||||
else:
|
||||
|
|
@ -417,7 +418,7 @@ class Placer(AppShell):
|
|||
else:
|
||||
if name == 'widget':
|
||||
# Record relationship between selected nodes and widget
|
||||
base.direct.selected.getWrtAll()
|
||||
ShowBaseGlobal.direct.selected.getWrtAll()
|
||||
# Update active node path
|
||||
self.setActiveNodePath(nodePath)
|
||||
|
||||
|
|
@ -449,7 +450,7 @@ class Placer(AppShell):
|
|||
if name == 'self':
|
||||
nodePath = self.tempCS
|
||||
elif name == 'selected':
|
||||
nodePath = base.direct.selected.last
|
||||
nodePath = ShowBaseGlobal.direct.selected.last
|
||||
# Add Combo box entry for this selected object
|
||||
self.addRefNodePath(nodePath)
|
||||
elif name == 'parent':
|
||||
|
|
@ -560,13 +561,13 @@ class Placer(AppShell):
|
|||
elif self.movementMode == 'Orbit:':
|
||||
self.xformOrbit(value, axis)
|
||||
if self.nodePathMenu.get() == 'widget':
|
||||
if base.direct.manipulationControl.fSetCoa:
|
||||
if ShowBaseGlobal.direct.manipulationControl.fSetCoa:
|
||||
# Update coa based on current widget position
|
||||
base.direct.selected.last.mCoa2Dnp.assign(
|
||||
base.direct.widget.getMat(base.direct.selected.last))
|
||||
ShowBaseGlobal.direct.selected.last.mCoa2Dnp.assign(
|
||||
ShowBaseGlobal.direct.widget.getMat(ShowBaseGlobal.direct.selected.last))
|
||||
else:
|
||||
# Move the objects with the widget
|
||||
base.direct.selected.moveWrtWidgetAll()
|
||||
ShowBaseGlobal.direct.selected.moveWrtWidgetAll()
|
||||
|
||||
def xformStart(self, data):
|
||||
# Record undo point
|
||||
|
|
@ -575,7 +576,7 @@ class Placer(AppShell):
|
|||
if self.nodePathMenu.get() == 'widget':
|
||||
taskMgr.remove('followSelectedNodePath')
|
||||
# Record relationship between selected nodes and widget
|
||||
base.direct.selected.getWrtAll()
|
||||
ShowBaseGlobal.direct.selected.getWrtAll()
|
||||
# Record initial state
|
||||
self.deltaHpr = self['nodePath'].getHpr(self.refCS)
|
||||
# Update placer to reflect new state
|
||||
|
|
@ -590,7 +591,7 @@ class Placer(AppShell):
|
|||
# If moving widget restart follow task
|
||||
if self.nodePathMenu.get() == 'widget':
|
||||
# Restart followSelectedNodePath task
|
||||
base.direct.manipulationControl.spawnFollowSelectedNodePathTask()
|
||||
ShowBaseGlobal.direct.manipulationControl.spawnFollowSelectedNodePathTask()
|
||||
|
||||
def xformRelative(self, value, axis):
|
||||
nodePath = self['nodePath']
|
||||
|
|
@ -729,7 +730,7 @@ class Placer(AppShell):
|
|||
self.xformStop(None)
|
||||
|
||||
def pushUndo(self, fResetRedo = 1):
|
||||
base.direct.pushUndo([self['nodePath']])
|
||||
ShowBaseGlobal.direct.pushUndo([self['nodePath']])
|
||||
|
||||
def undoHook(self, nodePathList = []):
|
||||
# Reflect new changes
|
||||
|
|
@ -744,7 +745,7 @@ class Placer(AppShell):
|
|||
self.undoButton.configure(state = 'disabled')
|
||||
|
||||
def pushRedo(self):
|
||||
base.direct.pushRedo([self['nodePath']])
|
||||
ShowBaseGlobal.direct.pushRedo([self['nodePath']])
|
||||
|
||||
def redoHook(self, nodePathList = []):
|
||||
# Reflect new changes
|
||||
|
|
|
|||
|
|
@ -79,13 +79,12 @@ class WxAppShell(wx.Frame):
|
|||
self.onDestroy(event)
|
||||
|
||||
# to close Panda
|
||||
try:
|
||||
base
|
||||
except NameError:
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
if hasattr(ShowBaseGlobal, 'base'):
|
||||
ShowBaseGlobal.base.userExit()
|
||||
else:
|
||||
sys.exit()
|
||||
|
||||
base.userExit()
|
||||
|
||||
### USER METHODS ###
|
||||
# To be overridden
|
||||
def appInit(self):
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ from direct.task.TaskManagerGlobal import taskMgr
|
|||
from .WxAppShell import WxAppShell
|
||||
from .ViewPort import Viewport, ViewportManager
|
||||
|
||||
from typing import Optional
|
||||
|
||||
ID_FOUR_VIEW = 401
|
||||
ID_TOP_VIEW = 402
|
||||
ID_FRONT_VIEW = 403
|
||||
|
|
@ -25,7 +27,7 @@ class WxPandaShell(WxAppShell):
|
|||
copyright = ('Copyright 2010 Disney Online Studios.' +
|
||||
'\nAll Rights Reserved.')
|
||||
|
||||
MENU_TEXTS = {
|
||||
MENU_TEXTS: dict[int, tuple[str, Optional[str]]] = {
|
||||
ID_FOUR_VIEW: ("Four Views", None),
|
||||
ID_TOP_VIEW: ("Top View", None),
|
||||
ID_FRONT_VIEW: ("Front View", None),
|
||||
|
|
@ -114,6 +116,7 @@ class WxPandaShell(WxAppShell):
|
|||
self.wxStep()
|
||||
ViewportManager.initializeAll()
|
||||
# Position the camera
|
||||
base = ShowBaseGlobal.base
|
||||
if base.trackball is not None:
|
||||
base.trackball.node().setPos(0, 30, 0)
|
||||
base.trackball.node().setHpr(0, 15, 0)
|
||||
|
|
@ -125,33 +128,34 @@ class WxPandaShell(WxAppShell):
|
|||
# initializing direct
|
||||
if self.fStartDirect:
|
||||
base.startDirect(fWantTk = 0, fWantWx = 0)
|
||||
direct = ShowBaseGlobal.direct
|
||||
|
||||
base.direct.disableMouseEvents()
|
||||
newMouseEvents = ["_le_per_%s"%x for x in base.direct.mouseEvents] +\
|
||||
["_le_fro_%s"%x for x in base.direct.mouseEvents] +\
|
||||
["_le_lef_%s"%x for x in base.direct.mouseEvents] +\
|
||||
["_le_top_%s"%x for x in base.direct.mouseEvents]
|
||||
base.direct.mouseEvents = newMouseEvents
|
||||
base.direct.enableMouseEvents()
|
||||
direct.disableMouseEvents()
|
||||
newMouseEvents = ["_le_per_%s"%x for x in direct.mouseEvents] +\
|
||||
["_le_fro_%s"%x for x in direct.mouseEvents] +\
|
||||
["_le_lef_%s"%x for x in direct.mouseEvents] +\
|
||||
["_le_top_%s"%x for x in direct.mouseEvents]
|
||||
direct.mouseEvents = newMouseEvents
|
||||
direct.enableMouseEvents()
|
||||
|
||||
base.direct.disableKeyEvents()
|
||||
keyEvents = ["_le_per_%s"%x for x in base.direct.keyEvents] +\
|
||||
["_le_fro_%s"%x for x in base.direct.keyEvents] +\
|
||||
["_le_lef_%s"%x for x in base.direct.keyEvents] +\
|
||||
["_le_top_%s"%x for x in base.direct.keyEvents]
|
||||
base.direct.keyEvents = keyEvents
|
||||
base.direct.enableKeyEvents()
|
||||
direct.disableKeyEvents()
|
||||
keyEvents = ["_le_per_%s"%x for x in direct.keyEvents] +\
|
||||
["_le_fro_%s"%x for x in direct.keyEvents] +\
|
||||
["_le_lef_%s"%x for x in direct.keyEvents] +\
|
||||
["_le_top_%s"%x for x in direct.keyEvents]
|
||||
direct.keyEvents = keyEvents
|
||||
direct.enableKeyEvents()
|
||||
|
||||
base.direct.disableModifierEvents()
|
||||
modifierEvents = ["_le_per_%s"%x for x in base.direct.modifierEvents] +\
|
||||
["_le_fro_%s"%x for x in base.direct.modifierEvents] +\
|
||||
["_le_lef_%s"%x for x in base.direct.modifierEvents] +\
|
||||
["_le_top_%s"%x for x in base.direct.modifierEvents]
|
||||
base.direct.modifierEvents = modifierEvents
|
||||
base.direct.enableModifierEvents()
|
||||
direct.disableModifierEvents()
|
||||
modifierEvents = ["_le_per_%s"%x for x in direct.modifierEvents] +\
|
||||
["_le_fro_%s"%x for x in direct.modifierEvents] +\
|
||||
["_le_lef_%s"%x for x in direct.modifierEvents] +\
|
||||
["_le_top_%s"%x for x in direct.modifierEvents]
|
||||
direct.modifierEvents = modifierEvents
|
||||
direct.enableModifierEvents()
|
||||
|
||||
base.direct.cameraControl.lockRoll = True
|
||||
base.direct.setFScaleWidgetByCam(1)
|
||||
direct.cameraControl.lockRoll = True
|
||||
direct.setFScaleWidgetByCam(1)
|
||||
|
||||
unpickables = [
|
||||
"z-guide",
|
||||
|
|
@ -172,31 +176,31 @@ class WxPandaShell(WxAppShell):
|
|||
"Sphere",]
|
||||
|
||||
for unpickable in unpickables:
|
||||
base.direct.addUnpickable(unpickable)
|
||||
direct.addUnpickable(unpickable)
|
||||
|
||||
base.direct.manipulationControl.optionalSkipFlags |= SKIP_UNPICKABLE
|
||||
base.direct.manipulationControl.fAllowMarquee = 1
|
||||
base.direct.manipulationControl.supportMultiView()
|
||||
base.direct.cameraControl.useMayaCamControls = 1
|
||||
base.direct.cameraControl.perspCollPlane = self.perspView.collPlane
|
||||
base.direct.cameraControl.perspCollPlane2 = self.perspView.collPlane2
|
||||
direct.manipulationControl.optionalSkipFlags |= SKIP_UNPICKABLE
|
||||
direct.manipulationControl.fAllowMarquee = 1
|
||||
direct.manipulationControl.supportMultiView()
|
||||
direct.cameraControl.useMayaCamControls = 1
|
||||
direct.cameraControl.perspCollPlane = self.perspView.collPlane
|
||||
direct.cameraControl.perspCollPlane2 = self.perspView.collPlane2
|
||||
|
||||
for widget in base.direct.manipulationControl.widgetList:
|
||||
for widget in direct.manipulationControl.widgetList:
|
||||
widget.setBin('gui-popup', 0)
|
||||
widget.setDepthTest(0)
|
||||
|
||||
# [gjeon] to intercept messages here
|
||||
base.direct.ignore('DIRECT-delete')
|
||||
base.direct.ignore('DIRECT-select')
|
||||
base.direct.ignore('DIRECT-preDeselectAll')
|
||||
base.direct.ignore('DIRECT-toggleWidgetVis')
|
||||
base.direct.fIgnoreDirectOnlyKeyMap = 1
|
||||
direct.ignore('DIRECT-delete')
|
||||
direct.ignore('DIRECT-select')
|
||||
direct.ignore('DIRECT-preDeselectAll')
|
||||
direct.ignore('DIRECT-toggleWidgetVis')
|
||||
direct.fIgnoreDirectOnlyKeyMap = 1
|
||||
|
||||
# [gjeon] do not use the old way of finding current DR
|
||||
base.direct.drList.tryToGetCurrentDr = False
|
||||
direct.drList.tryToGetCurrentDr = False
|
||||
|
||||
else:
|
||||
base.direct=None
|
||||
base.direct = None
|
||||
#base.closeWindow(base.win)
|
||||
base.win = base.winList[3]
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
* size.
|
||||
*/
|
||||
constexpr DeletedBufferChain::
|
||||
DeletedBufferChain(size_t buffer_size) : _buffer_size(buffer_size) {
|
||||
DeletedBufferChain(size_t buffer_size) noexcept : _buffer_size(buffer_size) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -77,22 +77,6 @@ operator < (const DeletedBufferChain &other) const {
|
|||
return _buffer_size < other._buffer_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a deleted chain of the given size.
|
||||
*/
|
||||
INLINE DeletedBufferChain *DeletedBufferChain::
|
||||
get_deleted_chain(size_t buffer_size) {
|
||||
// We must allocate at least this much space for bookkeeping reasons.
|
||||
buffer_size = (std::max)(buffer_size, sizeof(ObjectNode));
|
||||
|
||||
size_t index = ((buffer_size + sizeof(void *) - 1) / sizeof(void *)) - 1;
|
||||
if (index < num_small_deleted_chains) {
|
||||
return &_small_deleted_chains[index];
|
||||
} else {
|
||||
return get_large_deleted_chain((index + 1) * sizeof(void *));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts an ObjectNode* to a void* buffer.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -16,32 +16,10 @@
|
|||
|
||||
#include <set>
|
||||
|
||||
DeletedBufferChain DeletedBufferChain::_small_deleted_chains[DeletedBufferChain::num_small_deleted_chains] = {
|
||||
DeletedBufferChain(sizeof(void *)),
|
||||
DeletedBufferChain(sizeof(void *) * 2),
|
||||
DeletedBufferChain(sizeof(void *) * 3),
|
||||
DeletedBufferChain(sizeof(void *) * 4),
|
||||
DeletedBufferChain(sizeof(void *) * 5),
|
||||
DeletedBufferChain(sizeof(void *) * 6),
|
||||
DeletedBufferChain(sizeof(void *) * 7),
|
||||
DeletedBufferChain(sizeof(void *) * 8),
|
||||
DeletedBufferChain(sizeof(void *) * 9),
|
||||
DeletedBufferChain(sizeof(void *) * 10),
|
||||
DeletedBufferChain(sizeof(void *) * 11),
|
||||
DeletedBufferChain(sizeof(void *) * 12),
|
||||
DeletedBufferChain(sizeof(void *) * 13),
|
||||
DeletedBufferChain(sizeof(void *) * 14),
|
||||
DeletedBufferChain(sizeof(void *) * 15),
|
||||
DeletedBufferChain(sizeof(void *) * 16),
|
||||
DeletedBufferChain(sizeof(void *) * 17),
|
||||
DeletedBufferChain(sizeof(void *) * 18),
|
||||
DeletedBufferChain(sizeof(void *) * 19),
|
||||
DeletedBufferChain(sizeof(void *) * 20),
|
||||
DeletedBufferChain(sizeof(void *) * 21),
|
||||
DeletedBufferChain(sizeof(void *) * 22),
|
||||
DeletedBufferChain(sizeof(void *) * 23),
|
||||
DeletedBufferChain(sizeof(void *) * 24),
|
||||
};
|
||||
// This array stores the deleted chains for smaller sizes, starting with
|
||||
// sizeof(void *) and increasing in multiples thereof.
|
||||
static const size_t num_small_deleted_chains = 24;
|
||||
static DeletedBufferChain small_deleted_chains[num_small_deleted_chains] = {};
|
||||
|
||||
/**
|
||||
* Allocates the memory for a new buffer of the indicated size (which must be
|
||||
|
|
@ -49,6 +27,8 @@ DeletedBufferChain DeletedBufferChain::_small_deleted_chains[DeletedBufferChain:
|
|||
*/
|
||||
void *DeletedBufferChain::
|
||||
allocate(size_t size, TypeHandle type_handle) {
|
||||
assert(_buffer_size > 0);
|
||||
|
||||
#ifdef USE_DELETED_CHAIN
|
||||
// TAU_PROFILE("void *DeletedBufferChain::allocate(size_t, TypeHandle)", "
|
||||
// ", TAU_USER);
|
||||
|
|
@ -161,7 +141,18 @@ deallocate(void *ptr, TypeHandle type_handle) {
|
|||
* Returns a new DeletedBufferChain.
|
||||
*/
|
||||
DeletedBufferChain *DeletedBufferChain::
|
||||
get_large_deleted_chain(size_t buffer_size) {
|
||||
get_deleted_chain(size_t buffer_size) {
|
||||
// Common, smaller sized chains avoid the expensive locking and set
|
||||
// manipulation code further down.
|
||||
size_t index = ((buffer_size + sizeof(void *) - 1) / sizeof(void *));
|
||||
buffer_size = index * sizeof(void *);
|
||||
index--;
|
||||
if (index < num_small_deleted_chains) {
|
||||
DeletedBufferChain *chain = &small_deleted_chains[index];
|
||||
chain->_buffer_size = buffer_size;
|
||||
return chain;
|
||||
}
|
||||
|
||||
static MutexImpl lock;
|
||||
lock.lock();
|
||||
static std::set<DeletedBufferChain> deleted_chains;
|
||||
|
|
|
|||
|
|
@ -57,10 +57,9 @@ enum DeletedChainFlag : unsigned int {
|
|||
* Use MemoryHook to get a new DeletedBufferChain of a particular size.
|
||||
*/
|
||||
class EXPCL_DTOOL_DTOOLBASE DeletedBufferChain {
|
||||
protected:
|
||||
constexpr explicit DeletedBufferChain(size_t buffer_size);
|
||||
|
||||
public:
|
||||
constexpr DeletedBufferChain() = default;
|
||||
constexpr explicit DeletedBufferChain(size_t buffer_size) noexcept;
|
||||
INLINE DeletedBufferChain(DeletedBufferChain &&from) noexcept;
|
||||
INLINE DeletedBufferChain(const DeletedBufferChain ©);
|
||||
|
||||
|
|
@ -72,11 +71,9 @@ public:
|
|||
|
||||
INLINE bool operator < (const DeletedBufferChain &other) const;
|
||||
|
||||
static INLINE DeletedBufferChain *get_deleted_chain(size_t buffer_size);
|
||||
static DeletedBufferChain *get_deleted_chain(size_t buffer_size);
|
||||
|
||||
private:
|
||||
static DeletedBufferChain *get_large_deleted_chain(size_t buffer_size);
|
||||
|
||||
class ObjectNode {
|
||||
public:
|
||||
#ifdef USE_DELETEDCHAINFLAG
|
||||
|
|
@ -99,7 +96,7 @@ private:
|
|||
ObjectNode *_deleted_chain = nullptr;
|
||||
|
||||
MutexImpl _lock;
|
||||
const size_t _buffer_size;
|
||||
size_t _buffer_size = 0;
|
||||
|
||||
#ifndef USE_DELETEDCHAINFLAG
|
||||
// Without DELETEDCHAINFLAG, we don't even store the _flag member at all.
|
||||
|
|
@ -110,11 +107,6 @@ private:
|
|||
static const size_t flag_reserved_bytes = sizeof(AtomicAdjust::Integer);
|
||||
#endif // USE_DELETEDCHAINFLAG
|
||||
|
||||
// This array stores the deleted chains for smaller sizes, starting with
|
||||
// sizeof(void *) and increasing in multiples thereof.
|
||||
static const size_t num_small_deleted_chains = 24;
|
||||
static DeletedBufferChain _small_deleted_chains[num_small_deleted_chains];
|
||||
|
||||
friend class MemoryHook;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ static PyMemberDef standard_type_members[] = {
|
|||
{(char *)"this_const", T_BOOL, offsetof(Dtool_PyInstDef, _is_const), READONLY, (char *)"C++ 'this' const flag"},
|
||||
// {(char *)"this_signature", T_INT, offsetof(Dtool_PyInstDef, _signature),
|
||||
// READONLY, (char *)"A type check signature"},
|
||||
{(char *)"this_metatype", T_OBJECT, offsetof(Dtool_PyInstDef, _My_Type), READONLY, (char *)"The dtool meta object"},
|
||||
{(char *)"this_metatype", T_OBJECT_EX, offsetof(Dtool_PyInstDef, _My_Type), READONLY, (char *)"The dtool meta object"},
|
||||
{nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -241,6 +241,18 @@ INLINE PyObject *PyObject_CallMethodOneArg(PyObject *obj, PyObject *name, PyObje
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Python 3.12 */
|
||||
|
||||
#if PY_VERSION_HEX < 0x030C0000
|
||||
# define PyLong_IsNonNegative(value) (Py_SIZE((value)) >= 0)
|
||||
#else
|
||||
INLINE bool PyLong_IsNonNegative(PyObject *value) {
|
||||
int overflow = 0;
|
||||
long longval = PyLong_AsLongAndOverflow(value, &overflow);
|
||||
return overflow == 1 || longval >= 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Other Python implementations */
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@ import os
|
|||
import sys
|
||||
from optparse import OptionParser
|
||||
from makepandacore import *
|
||||
|
||||
# DO NOT CHANGE TO sysconfig - see GitHub issue #1230
|
||||
from distutils.sysconfig import get_python_lib
|
||||
from locations import get_python_lib
|
||||
|
||||
|
||||
MIME_INFO = (
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
__all__ = [
|
||||
'get_python_inc',
|
||||
'get_config_var',
|
||||
'get_python_version',
|
||||
'PREFIX',
|
||||
'get_python_lib',
|
||||
'get_config_vars',
|
||||
]
|
||||
|
||||
import sys
|
||||
|
||||
if sys.version_info < (3, 12):
|
||||
from distutils.sysconfig import *
|
||||
else:
|
||||
from sysconfig import *
|
||||
|
||||
PREFIX = get_config_var('prefix')
|
||||
|
||||
def get_python_inc(plat_specific=False):
|
||||
path_name = 'platinclude' if plat_specific else 'include'
|
||||
return get_path(path_name)
|
||||
|
||||
def get_python_lib(plat_specific=False, standard_lib=False):
|
||||
if standard_lib:
|
||||
path_name = 'stdlib'
|
||||
if plat_specific:
|
||||
path_name = 'plat' + path_name
|
||||
elif plat_specific:
|
||||
path_name = 'platlib'
|
||||
else:
|
||||
path_name = 'purelib'
|
||||
return get_path(path_name)
|
||||
|
|
@ -942,8 +942,7 @@ def MakeInstallerAndroid(version, **kwargs):
|
|||
shutil.copy(os.path.join(source_dir, base), target)
|
||||
|
||||
# Copy the Python standard library to the .apk as well.
|
||||
# DO NOT CHANGE TO sysconfig - see #1230
|
||||
from distutils.sysconfig import get_python_lib
|
||||
from locations import get_python_lib
|
||||
stdlib_source = get_python_lib(False, True)
|
||||
stdlib_target = os.path.join("apkroot", "lib", "python{0}.{1}".format(*sys.version_info))
|
||||
copy_python_tree(stdlib_source, stdlib_target)
|
||||
|
|
|
|||
|
|
@ -30,12 +30,10 @@ except:
|
|||
print("Please install the development package of Python and try again.")
|
||||
exit(1)
|
||||
|
||||
if sys.version_info >= (3, 10):
|
||||
from sysconfig import get_platform
|
||||
else:
|
||||
from distutils.util import get_platform
|
||||
from makepandacore import *
|
||||
|
||||
from sysconfig import get_platform
|
||||
|
||||
try:
|
||||
import zlib
|
||||
except:
|
||||
|
|
@ -368,6 +366,12 @@ if GetHost() == "darwin":
|
|||
if VERSION is None:
|
||||
# Take the value from the setup.cfg file.
|
||||
VERSION = GetMetadataValue('version')
|
||||
match = re.match(r'^\d+\.\d+(\.\d+)+', VERSION)
|
||||
if not match:
|
||||
exit("Invalid version %s in setup.cfg, three digits are required" % (VERSION))
|
||||
if WHLVERSION is None:
|
||||
WHLVERSION = VERSION
|
||||
VERSION = match.group()
|
||||
|
||||
if WHLVERSION is None:
|
||||
WHLVERSION = VERSION
|
||||
|
|
@ -2689,11 +2693,18 @@ template class CheckPandaVersion<void>;
|
|||
|
||||
|
||||
def CreatePandaVersionFiles():
|
||||
version1=int(VERSION.split(".")[0])
|
||||
version2=int(VERSION.split(".")[1])
|
||||
version3=int(VERSION.split(".")[2])
|
||||
nversion=version1*1000000+version2*1000+version3
|
||||
if (DISTRIBUTOR != "cmu"):
|
||||
parts = VERSION.split(".", 2)
|
||||
version1 = int(parts[0])
|
||||
version2 = int(parts[1])
|
||||
version3 = 0
|
||||
if len(parts) > 2:
|
||||
for c in parts[2]:
|
||||
if c.isdigit():
|
||||
version3 = version3 * 10 + ord(c) - 48
|
||||
else:
|
||||
break
|
||||
nversion = version1 * 1000000 + version2 * 1000 + version3
|
||||
if DISTRIBUTOR != "cmu":
|
||||
# Subtract 1 if we are not an official version.
|
||||
nversion -= 1
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
########################################################################
|
||||
|
||||
import configparser
|
||||
from distutils import sysconfig # DO NOT CHANGE to sysconfig - see #1230
|
||||
import fnmatch
|
||||
import getpass
|
||||
import glob
|
||||
|
|
@ -21,6 +20,7 @@ import sys
|
|||
import threading
|
||||
import _thread as thread
|
||||
import time
|
||||
import locations
|
||||
|
||||
SUFFIX_INC = [".cxx",".cpp",".c",".h",".I",".yxx",".lxx",".mm",".rc",".r"]
|
||||
SUFFIX_DLL = [".dll",".dlo",".dle",".dli",".dlm",".mll",".exe",".pyd",".ocx"]
|
||||
|
|
@ -2195,7 +2195,7 @@ def SdkLocatePython(prefer_thirdparty_python=False):
|
|||
# On macOS, search for the Python framework directory matching the
|
||||
# version number of our current Python version.
|
||||
sysroot = SDK.get("MACOSX", "")
|
||||
version = sysconfig.get_python_version()
|
||||
version = locations.get_python_version()
|
||||
|
||||
py_fwx = "{0}/System/Library/Frameworks/Python.framework/Versions/{1}".format(sysroot, version)
|
||||
|
||||
|
|
@ -2227,19 +2227,19 @@ def SdkLocatePython(prefer_thirdparty_python=False):
|
|||
LibDirectory("PYTHON", py_fwx + "/lib")
|
||||
|
||||
#elif GetTarget() == 'windows':
|
||||
# SDK["PYTHON"] = os.path.dirname(sysconfig.get_python_inc())
|
||||
# SDK["PYTHONVERSION"] = "python" + sysconfig.get_python_version()
|
||||
# SDK["PYTHON"] = os.path.dirname(locations.get_python_inc())
|
||||
# SDK["PYTHONVERSION"] = "python" + locations.get_python_version()
|
||||
# SDK["PYTHONEXEC"] = sys.executable
|
||||
|
||||
else:
|
||||
SDK["PYTHON"] = sysconfig.get_python_inc()
|
||||
SDK["PYTHONVERSION"] = "python" + sysconfig.get_python_version() + abiflags
|
||||
SDK["PYTHON"] = locations.get_python_inc()
|
||||
SDK["PYTHONVERSION"] = "python" + locations.get_python_version() + abiflags
|
||||
SDK["PYTHONEXEC"] = os.path.realpath(sys.executable)
|
||||
|
||||
if CrossCompiling():
|
||||
# We need a version of Python we can run.
|
||||
SDK["PYTHONEXEC"] = sys.executable
|
||||
host_version = "python" + sysconfig.get_python_version() + abiflags
|
||||
host_version = "python" + locations.get_python_version() + abiflags
|
||||
if SDK["PYTHONVERSION"] != host_version:
|
||||
exit("Host Python version (%s) must be the same as target Python version (%s)!" % (host_version, SDK["PYTHONVERSION"]))
|
||||
|
||||
|
|
@ -3393,7 +3393,7 @@ def GetExtensionSuffix():
|
|||
|
||||
def GetPythonABI():
|
||||
if not CrossCompiling():
|
||||
soabi = sysconfig.get_config_var('SOABI')
|
||||
soabi = locations.get_config_var('SOABI')
|
||||
if soabi:
|
||||
return soabi
|
||||
|
||||
|
|
@ -3514,8 +3514,8 @@ def GetCurrentPythonVersionInfo():
|
|||
"soabi": GetPythonABI(),
|
||||
"ext_suffix": GetExtensionSuffix(),
|
||||
"executable": sys.executable,
|
||||
"purelib": sysconfig.get_python_lib(False),
|
||||
"platlib": sysconfig.get_python_lib(True),
|
||||
"purelib": locations.get_python_lib(False),
|
||||
"platlib": locations.get_python_lib(True),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,11 @@ import tempfile
|
|||
import subprocess
|
||||
import time
|
||||
import struct
|
||||
from sysconfig import get_platform, get_config_var
|
||||
from optparse import OptionParser
|
||||
from base64 import urlsafe_b64encode
|
||||
from makepandacore import LocateBinary, GetExtensionSuffix, SetVerbose, GetVerbose, GetMetadataValue, CrossCompiling, GetThirdpartyDir, SDK, GetStrip
|
||||
from locations import get_config_var
|
||||
from sysconfig import get_platform
|
||||
|
||||
|
||||
def get_abi_tag():
|
||||
|
|
|
|||
|
|
@ -40,12 +40,36 @@ CocoaGraphicsPipe(CGDirectDisplayID display) : _display(display) {
|
|||
[thread start];
|
||||
[thread autorelease];
|
||||
|
||||
// If the application is dpi-aware, iterate over all the screens to find the
|
||||
// one with our display ID and get the backing scale factor to configure the
|
||||
// detected display zoom. Otherwise the detected display zoom keeps its
|
||||
// default value of 1.0
|
||||
|
||||
if (dpi_aware) {
|
||||
NSScreen *screen;
|
||||
NSEnumerator *e = [[NSScreen screens] objectEnumerator];
|
||||
while (screen = (NSScreen *) [e nextObject]) {
|
||||
NSNumber *num = [[screen deviceDescription] objectForKey: @"NSScreenNumber"];
|
||||
if (_display == (CGDirectDisplayID) [num longValue]) {
|
||||
set_detected_display_zoom([screen backingScaleFactor]);
|
||||
if (cocoadisplay_cat.is_debug()) {
|
||||
cocoadisplay_cat.debug()
|
||||
<< "Display zoom is " << [screen backingScaleFactor] << "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We used to also obtain the corresponding NSScreen here, but this causes
|
||||
// the application icon to start bouncing, which may be undesirable for
|
||||
// apps that will never open a window.
|
||||
|
||||
_display_width = CGDisplayPixelsWide(_display);
|
||||
_display_height = CGDisplayPixelsHigh(_display);
|
||||
// Although the name of these functions mention pixels, they actually return
|
||||
// display points, we use the detected display zoom to transform the values
|
||||
// into pixels.
|
||||
_display_width = CGDisplayPixelsWide(_display) * _detected_display_zoom;
|
||||
_display_height = CGDisplayPixelsHigh(_display) * _detected_display_zoom;
|
||||
load_display_information();
|
||||
|
||||
if (cocoadisplay_cat.is_debug()) {
|
||||
|
|
@ -64,19 +88,36 @@ load_display_information() {
|
|||
// _display_information->_device_id = CGDisplaySerialNumber(_display);
|
||||
|
||||
// Display modes
|
||||
CFDictionaryRef options = NULL;
|
||||
const CFStringRef dictkeys[] = {kCGDisplayShowDuplicateLowResolutionModes};
|
||||
const CFBooleanRef dictvalues[] = {kCFBooleanTrue};
|
||||
options = CFDictionaryCreate(NULL,
|
||||
(const void **)dictkeys,
|
||||
(const void **)dictvalues,
|
||||
1,
|
||||
&kCFCopyStringDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
size_t num_modes = 0;
|
||||
CFArrayRef modes = CGDisplayCopyAllDisplayModes(_display, NULL);
|
||||
CFArrayRef modes = CGDisplayCopyAllDisplayModes(_display, options);
|
||||
if (modes != NULL) {
|
||||
num_modes = CFArrayGetCount(modes);
|
||||
_display_information->_total_display_modes = num_modes;
|
||||
_display_information->_display_mode_array = new DisplayMode[num_modes];
|
||||
}
|
||||
if (options != NULL) {
|
||||
CFRelease(options);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_modes; ++i) {
|
||||
CGDisplayModeRef mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
|
||||
|
||||
_display_information->_display_mode_array[i].width = CGDisplayModeGetWidth(mode);
|
||||
_display_information->_display_mode_array[i].height = CGDisplayModeGetHeight(mode);
|
||||
if (dpi_aware) {
|
||||
_display_information->_display_mode_array[i].width = CGDisplayModeGetPixelWidth(mode);
|
||||
_display_information->_display_mode_array[i].height = CGDisplayModeGetPixelHeight(mode);
|
||||
} else {
|
||||
_display_information->_display_mode_array[i].width = CGDisplayModeGetWidth(mode);
|
||||
_display_information->_display_mode_array[i].height = CGDisplayModeGetHeight(mode);
|
||||
}
|
||||
_display_information->_display_mode_array[i].refresh_rate = CGDisplayModeGetRefreshRate(mode);
|
||||
_display_information->_display_mode_array[i].fullscreen_only = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ public:
|
|||
void handle_minimize_event(bool minimized);
|
||||
void handle_maximize_event(bool maximized);
|
||||
void handle_foreground_event(bool foreground);
|
||||
void handle_backing_change_event();
|
||||
bool handle_close_request();
|
||||
void handle_close_event();
|
||||
void handle_key_event(NSEvent *event);
|
||||
|
|
|
|||
|
|
@ -132,13 +132,20 @@ move_pointer(int device, int x, int y) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Mouse position is expressed in screen points and not pixels, but in Panda3D
|
||||
// we are using pixel coordinates.
|
||||
// Instead of using convertPointFromBacking and have complex logic to cope with
|
||||
// the change of coordinate system, we cheat and directly use the contents scale
|
||||
// of the view layer to convert pixel coordinates into screen point coordinates.
|
||||
CGFloat contents_scale = _view.layer.contentsScale;
|
||||
if (device == 0) {
|
||||
CGPoint point;
|
||||
if (_properties.get_fullscreen()) {
|
||||
point = CGPointMake(x, y);
|
||||
point = CGPointMake(float(x) / contents_scale,
|
||||
float(y) / contents_scale);
|
||||
} else {
|
||||
point = CGPointMake(x + _properties.get_x_origin(),
|
||||
y + _properties.get_y_origin());
|
||||
point = CGPointMake((float(x) + _properties.get_x_origin()) / contents_scale,
|
||||
(float(y) + _properties.get_y_origin()) / contents_scale);
|
||||
}
|
||||
|
||||
if (CGWarpMouseCursorPosition(point) == kCGErrorSuccess) {
|
||||
|
|
@ -302,35 +309,89 @@ open_window() {
|
|||
}
|
||||
}
|
||||
|
||||
// Configure the origin and the size of the window.
|
||||
// On macOS, screen coordinates are expressed in "points" which are independant
|
||||
// of the pixel density of the screen. Panda3D however, expresses the size and
|
||||
// origin of a window in pixels.
|
||||
// So, when opening a window, we need to convert the origin and size from pixel
|
||||
// units into point units. However, this conversion depends on the pixel density
|
||||
// of the screen, the backing scale factor.
|
||||
// As the origin and size of a window depends on the size of the screen of the
|
||||
// parent view, their size must be converted first from points to pixels.
|
||||
// If a window (or a view) is not configured to support high-dpi screen, macOS
|
||||
// will upscale the window (or view) when displayed on a high-dpi screen.
|
||||
// Therefore its backing scale factor will always be 1.0
|
||||
// In a Panda3D application, windows are always configured as high resolution
|
||||
// capable, but the view is only configured as high resolution if the dpi-aware
|
||||
// configuration flag is set.
|
||||
// If the app is not dpi-aware, we must upscale its size and origin from points
|
||||
// into pixels as the window is always high resolution capable.
|
||||
|
||||
// Center the window if coordinates were set to -1 or -2 TODO: perhaps in
|
||||
// future, in the case of -1, it should use the origin used in a previous
|
||||
// run of Panda
|
||||
|
||||
// Size of the requested window
|
||||
NSSize size = NSMakeSize(_properties.get_x_size(), _properties.get_y_size());
|
||||
NSRect container;
|
||||
CGFloat backing_scale_factor = screen.backingScaleFactor;
|
||||
if (parent_nsview != NULL) {
|
||||
container = [parent_nsview bounds];
|
||||
// Convert parent view bounds into pixel units.
|
||||
container = [parent_nsview convertRectToBacking:[parent_nsview bounds]];
|
||||
// If the app is not dpi-aware, we must convert its size from points into
|
||||
// pixels as the window is always high resolution capable
|
||||
if (!dpi_aware) {
|
||||
size = [parent_nsview convertSizeToBacking:size];
|
||||
}
|
||||
} else {
|
||||
container = [screen frame];
|
||||
container.origin = NSMakePoint(0, 0);
|
||||
container = [screen convertRectToBacking:container];
|
||||
if (!dpi_aware) {
|
||||
// Weirdly NSScreen does not respond to convertSizeToBacking, so we have to
|
||||
// create a dummy rect just for converting the window size.
|
||||
NSRect rect;
|
||||
rect.origin = NSMakePoint(0, 0);
|
||||
rect.size = size;
|
||||
rect = [screen convertRectToBacking:rect];
|
||||
size = rect.size;
|
||||
}
|
||||
}
|
||||
int x = _properties.get_x_origin();
|
||||
int y = _properties.get_y_origin();
|
||||
|
||||
// As we are converting a single value and the view is not created yet, it's
|
||||
// easier to simply use the backing scale factor and don't bother with
|
||||
// coordinate system transformations.
|
||||
if (x < 0) {
|
||||
x = floor(container.size.width / 2 - _properties.get_x_size() / 2);
|
||||
x = floor(container.size.width / 2 - size.width / 2);
|
||||
} else if (!dpi_aware) {
|
||||
x *= backing_scale_factor;
|
||||
}
|
||||
if (y < 0) {
|
||||
y = floor(container.size.height / 2 - _properties.get_y_size() / 2);
|
||||
y = floor(container.size.height / 2 - size.height / 2);
|
||||
} else if (!dpi_aware) {
|
||||
y *= backing_scale_factor;
|
||||
}
|
||||
if (dpi_aware) {
|
||||
_properties.set_origin(x, y);
|
||||
} else {
|
||||
_properties.set_origin(x / backing_scale_factor, y / backing_scale_factor);
|
||||
}
|
||||
_properties.set_origin(x, y);
|
||||
|
||||
if (_parent_window_handle == (WindowHandle *)NULL) {
|
||||
// Content rectangle
|
||||
NSRect rect;
|
||||
if (_properties.get_fullscreen()) {
|
||||
rect = container;
|
||||
rect = [screen convertRectFromBacking:container];
|
||||
} else {
|
||||
rect = NSMakeRect(x, container.size.height - _properties.get_y_size() - y,
|
||||
_properties.get_x_size(), _properties.get_y_size());
|
||||
rect = NSMakeRect(x, container.size.height - size.height - y,
|
||||
size.width, size.height);
|
||||
if (parent_nsview != NULL) {
|
||||
rect = [parent_nsview convertRectFromBacking:rect];
|
||||
} else {
|
||||
rect = [screen convertRectFromBacking:rect];
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the window decorations
|
||||
|
|
@ -388,8 +449,10 @@ open_window() {
|
|||
_parent_window_handle->attach_child(_window_handle);
|
||||
}
|
||||
|
||||
// Always disable application HiDPI support, Cocoa will do the eventual upscaling for us.
|
||||
[_view setWantsBestResolutionOpenGLSurface:NO];
|
||||
// Configure the view to be high resolution capable using the dpi-aware
|
||||
// configuration flag. If dpi-aware is false, macOS will upscale the view
|
||||
// for us.
|
||||
[_view setWantsBestResolutionOpenGLSurface:dpi_aware];
|
||||
if (_properties.has_icon_filename()) {
|
||||
NSImage *image = load_image(_properties.get_icon_filename());
|
||||
if (image != nil) {
|
||||
|
|
@ -596,22 +659,6 @@ set_properties_now(WindowProperties &properties) {
|
|||
}
|
||||
|
||||
if (switched) {
|
||||
if (_window != nil) {
|
||||
// For some reason, setting the style mask makes it give up its
|
||||
// first-responder status. And for some reason, we need to first
|
||||
// restore the window to normal level before we switch fullscreen,
|
||||
// otherwise we may get a black bar if we're currently on Z_top.
|
||||
if (_properties.get_z_order() != WindowProperties::Z_normal) {
|
||||
[_window setLevel: NSNormalWindowLevel];
|
||||
}
|
||||
if ([_window respondsToSelector:@selector(setStyleMask:)]) {
|
||||
[_window setStyleMask:NSBorderlessWindowMask];
|
||||
}
|
||||
[_window makeFirstResponder:_view];
|
||||
[_window setLevel:CGShieldingWindowLevel()];
|
||||
[_window makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
// We've already set the size property this way; clear it.
|
||||
properties.clear_size();
|
||||
_properties.set_size(width, height);
|
||||
|
|
@ -684,6 +731,9 @@ set_properties_now(WindowProperties &properties) {
|
|||
NSMiniaturizableWindowMask | NSResizableWindowMask ];
|
||||
}
|
||||
[_window makeFirstResponder:_view];
|
||||
// Resize event fired by makeFirstResponder has an invalid backing scale factor
|
||||
// The actual size must be reset afterward
|
||||
handle_resize_event();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -705,6 +755,9 @@ set_properties_now(WindowProperties &properties) {
|
|||
NSMiniaturizableWindowMask | NSResizableWindowMask ];
|
||||
}
|
||||
[_window makeFirstResponder:_view];
|
||||
// Resize event fired by makeFirstResponder has an invalid backing scale factor
|
||||
// The actual size must be reset afterward
|
||||
handle_resize_event();
|
||||
}
|
||||
|
||||
properties.clear_undecorated();
|
||||
|
|
@ -715,10 +768,13 @@ set_properties_now(WindowProperties &properties) {
|
|||
int height = properties.get_y_size();
|
||||
|
||||
if (!_properties.get_fullscreen()) {
|
||||
// We use the view, not the window, to convert the frame size, expressed
|
||||
// in pixels, into points as the "dpi awareness" is managed by the view.
|
||||
NSSize size = [_view convertSizeFromBacking:NSMakeSize(width, height)];
|
||||
if (_window != nil) {
|
||||
[_window setContentSize:NSMakeSize(width, height)];
|
||||
[_window setContentSize:size];
|
||||
}
|
||||
[_view setFrameSize:NSMakeSize(width, height)];
|
||||
[_view setFrameSize:size];
|
||||
|
||||
if (cocoadisplay_cat.is_debug()) {
|
||||
cocoadisplay_cat.debug()
|
||||
|
|
@ -768,12 +824,14 @@ set_properties_now(WindowProperties &properties) {
|
|||
// Get the frame for the screen
|
||||
NSRect frame;
|
||||
NSRect container;
|
||||
// Note again that we are using the view to convert the frame and container
|
||||
// size from points into pixels.
|
||||
if (_window != nil) {
|
||||
NSRect window_frame = [_window frame];
|
||||
frame = [_window contentRectForFrameRect:window_frame];
|
||||
frame = [_view convertRectToBacking:[_window contentRectForFrameRect:window_frame]];
|
||||
NSScreen *screen = [_window screen];
|
||||
nassertv(screen != nil);
|
||||
container = [screen frame];
|
||||
container = [_view convertRectToBacking:[screen frame]];
|
||||
|
||||
// Prevent the centering from overlapping the Dock
|
||||
if (y < 0) {
|
||||
|
|
@ -783,8 +841,8 @@ set_properties_now(WindowProperties &properties) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
frame = [_view frame];
|
||||
container = [[_view superview] frame];
|
||||
frame = [_view convertRectToBacking:[_view frame]];
|
||||
container = [[_view superview] convertRectToBacking:[[_view superview] frame]];
|
||||
}
|
||||
|
||||
if (x < 0) {
|
||||
|
|
@ -795,22 +853,22 @@ set_properties_now(WindowProperties &properties) {
|
|||
}
|
||||
_properties.set_origin(x, y);
|
||||
|
||||
if (!_properties.get_fullscreen()) {
|
||||
// Remember, Mac OS X coordinates are flipped in the vertical axis.
|
||||
frame.origin.x = x;
|
||||
frame.origin.y = container.size.height - y - frame.size.height;
|
||||
frame.origin.x = x;
|
||||
// Y coordinate in backing store is not flipped, but origin is still at the bottom left
|
||||
frame.origin.y = y - container.size.height;
|
||||
|
||||
if (cocoadisplay_cat.is_debug()) {
|
||||
cocoadisplay_cat.debug()
|
||||
<< "Setting window content origin to "
|
||||
<< frame.origin.x << ", " << frame.origin.y << "\n";
|
||||
}
|
||||
if (cocoadisplay_cat.is_debug()) {
|
||||
cocoadisplay_cat.debug()
|
||||
<< "Setting window content origin to "
|
||||
<< frame.origin.x << ", " << frame.origin.y << "\n";
|
||||
}
|
||||
|
||||
if (_window != nil) {
|
||||
[_window setFrame:[_window frameRectForContentRect:frame] display:NO];
|
||||
} else {
|
||||
[_view setFrame:frame];
|
||||
}
|
||||
if (_window != nil) {
|
||||
frame = [_view convertRectFromBacking:frame];
|
||||
[_window setFrame:[_window frameRectForContentRect:frame] display:NO];
|
||||
} else {
|
||||
frame = [_view convertRectFromBacking:frame];
|
||||
[_view setFrame:frame];
|
||||
}
|
||||
properties.clear_origin();
|
||||
}
|
||||
|
|
@ -957,24 +1015,20 @@ unbind_context() {
|
|||
CFMutableArrayRef CocoaGraphicsWindow::
|
||||
find_display_modes(int width, int height) {
|
||||
CFDictionaryRef options = NULL;
|
||||
// On macOS 10.15+ (Catalina), we want to select the display mode with the
|
||||
// samescaling factor as the current view to avoid cropping or scaling issues.
|
||||
// This is a workaround until HiDPI display or scaling factor is properly
|
||||
// handled. CGDisplayCopyAllDisplayModes() does not return upscaled display
|
||||
// mode unless explicitly asked with kCGDisplayShowDuplicateLowResolutionModes
|
||||
// We want to select the display mode with the same scaling factor as the
|
||||
// current view to avoid cropping or scaling issues.
|
||||
// CGDisplayCopyAllDisplayModes() does not return upscaled display modes
|
||||
// nor the current mode, unless explicitly asked with
|
||||
// kCGDisplayShowDuplicateLowResolutionModes
|
||||
// (which is undocumented...).
|
||||
bool macos_10_15_or_higher = false;
|
||||
if (@available(macOS 10.15, *)) {
|
||||
const CFStringRef dictkeys[] = {kCGDisplayShowDuplicateLowResolutionModes};
|
||||
const CFBooleanRef dictvalues[] = {kCFBooleanTrue};
|
||||
options = CFDictionaryCreate(NULL,
|
||||
(const void **)dictkeys,
|
||||
(const void **)dictvalues,
|
||||
1,
|
||||
&kCFCopyStringDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
macos_10_15_or_higher = true;
|
||||
}
|
||||
const CFStringRef dictkeys[] = {kCGDisplayShowDuplicateLowResolutionModes};
|
||||
const CFBooleanRef dictvalues[] = {kCFBooleanTrue};
|
||||
options = CFDictionaryCreate(NULL,
|
||||
(const void **)dictkeys,
|
||||
(const void **)dictvalues,
|
||||
1,
|
||||
&kCFCopyStringDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
CFMutableArrayRef valid_modes;
|
||||
valid_modes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
|
||||
|
||||
|
|
@ -985,29 +1039,39 @@ find_display_modes(int width, int height) {
|
|||
|
||||
size_t num_modes = CFArrayGetCount(modes);
|
||||
CGDisplayModeRef mode;
|
||||
|
||||
// Get the current refresh rate and pixel encoding.
|
||||
CFStringRef current_pixel_encoding;
|
||||
double refresh_rate;
|
||||
mode = CGDisplayCopyDisplayMode(_display);
|
||||
|
||||
// Calculate requested display size and pixel size
|
||||
CGSize display_size;
|
||||
CGSize pixel_size;
|
||||
if (dpi_aware) {
|
||||
pixel_size = NSMakeSize(width, height);
|
||||
display_size = [_view convertSizeFromBacking:pixel_size];
|
||||
} else {
|
||||
display_size = NSMakeSize(width, height);
|
||||
// Calculate the pixel width and height of the fullscreen mode we want using
|
||||
// the current display mode dimensions and pixel dimensions.
|
||||
size_t pixel_width = (size_t(width) * CGDisplayModeGetPixelWidth(mode)) / CGDisplayModeGetWidth(mode);
|
||||
size_t pixel_height = (size_t(height) * CGDisplayModeGetPixelHeight(mode)) / CGDisplayModeGetHeight(mode);
|
||||
pixel_size = NSMakeSize(pixel_width, pixel_height);
|
||||
}
|
||||
|
||||
// First check if the current mode is adequate.
|
||||
// This test not done for macOS 10.15 and above as the mode resolution is
|
||||
// not enough to identify a mode.
|
||||
if (!macos_10_15_or_higher &&
|
||||
CGDisplayModeGetWidth(mode) == width &&
|
||||
CGDisplayModeGetHeight(mode) == height) {
|
||||
if (CGDisplayModeGetWidth(mode) == display_size.width &&
|
||||
CGDisplayModeGetHeight(mode) == display_size.height &&
|
||||
CGDisplayModeGetPixelWidth(mode) == pixel_size.width &&
|
||||
CGDisplayModeGetPixelHeight(mode) == pixel_size.height) {
|
||||
CFArrayAppendValue(valid_modes, mode);
|
||||
CGDisplayModeRelease(mode);
|
||||
return valid_modes;
|
||||
}
|
||||
|
||||
// Get the current refresh rate and pixel encoding.
|
||||
CFStringRef current_pixel_encoding;
|
||||
double refresh_rate;
|
||||
|
||||
current_pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
|
||||
refresh_rate = CGDisplayModeGetRefreshRate(mode);
|
||||
// Calculate the pixel width and height of the fullscreen mode we want using
|
||||
// the currentdisplay mode dimensions and pixel dimensions.
|
||||
size_t expected_pixel_width = (size_t(width) * CGDisplayModeGetPixelWidth(mode)) / CGDisplayModeGetWidth(mode);
|
||||
size_t expected_pixel_height = (size_t(height) * CGDisplayModeGetPixelHeight(mode)) / CGDisplayModeGetHeight(mode);
|
||||
CGDisplayModeRelease(mode);
|
||||
|
||||
for (size_t i = 0; i < num_modes; ++i) {
|
||||
|
|
@ -1015,17 +1079,15 @@ find_display_modes(int width, int height) {
|
|||
|
||||
CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
|
||||
|
||||
// As explained above, we want to select the fullscreen display mode using
|
||||
// the same scaling factor, but only for MacOS 10.15+ To do this we check
|
||||
// the mode width and height but also actual pixel widh and height.
|
||||
if (CGDisplayModeGetWidth(mode) == width &&
|
||||
CGDisplayModeGetHeight(mode) == height &&
|
||||
// We select the fullscreen display mode using he same scaling factor
|
||||
// To do this we check the mode width and height but also actual pixel widh
|
||||
// and height.
|
||||
if (CGDisplayModeGetWidth(mode) == display_size.width &&
|
||||
CGDisplayModeGetHeight(mode) == display_size.height &&
|
||||
(int)(CGDisplayModeGetRefreshRate(mode) + 0.5) == (int)(refresh_rate + 0.5) &&
|
||||
(!macos_10_15_or_higher ||
|
||||
(CGDisplayModeGetPixelWidth(mode) == expected_pixel_width &&
|
||||
CGDisplayModeGetPixelHeight(mode) == expected_pixel_height)) &&
|
||||
CGDisplayModeGetPixelWidth(mode) == pixel_size.width &&
|
||||
CGDisplayModeGetPixelHeight(mode) == pixel_size.height &&
|
||||
CFStringCompare(pixel_encoding, current_pixel_encoding, 0) == kCFCompareEqualTo) {
|
||||
|
||||
if (CGDisplayModeGetRefreshRate(mode) == refresh_rate) {
|
||||
// Exact match for refresh rate, prioritize this.
|
||||
CFArrayInsertValueAtIndex(valid_modes, 0, mode);
|
||||
|
|
@ -1103,14 +1165,25 @@ do_switch_fullscreen(CGDisplayModeRef mode) {
|
|||
|
||||
NSRect frame = [[[_view window] screen] frame];
|
||||
if (cocoadisplay_cat.is_debug()) {
|
||||
NSString *str = NSStringFromRect(frame);
|
||||
NSString *str = NSStringFromSize([_view convertSizeToBacking:frame.size]);
|
||||
cocoadisplay_cat.debug()
|
||||
<< "Switched to fullscreen, screen rect is now " << [str UTF8String] << "\n";
|
||||
<< "Switched to fullscreen, screen size is now " << [str UTF8String] << "\n";
|
||||
}
|
||||
|
||||
if (_window != nil) {
|
||||
// For some reason, setting the style mask makes it give up its
|
||||
// first-responder status.
|
||||
if ([_window respondsToSelector:@selector(setStyleMask:)]) {
|
||||
[_window setStyleMask:NSBorderlessWindowMask];
|
||||
}
|
||||
[_window makeFirstResponder:_view];
|
||||
[_window setLevel:CGShieldingWindowLevel()];
|
||||
[_window makeKeyAndOrderFront:nil];
|
||||
|
||||
// Window and view frame must be updated *after* the window reconfiguration
|
||||
// or the size is not set properly !
|
||||
[_window setFrame:frame display:YES];
|
||||
[_view setFrame:NSMakeRect(0, 0, frame.size.width, frame.size.height)];
|
||||
[_view setFrame:frame];
|
||||
[_window update];
|
||||
}
|
||||
}
|
||||
|
|
@ -1252,19 +1325,25 @@ load_cursor(const Filename &filename) {
|
|||
*/
|
||||
void CocoaGraphicsWindow::
|
||||
handle_move_event() {
|
||||
// Remember, Mac OS X uses flipped coordinates
|
||||
NSRect frame;
|
||||
NSRect container;
|
||||
int x, y;
|
||||
// Again, we are using the view to convert the frame and container size from
|
||||
// points to pixels.
|
||||
if (_window == nil) {
|
||||
frame = [_view frame];
|
||||
x = frame.origin.x;
|
||||
y = [[_view superview] bounds].size.height - frame.origin.y - frame.size.height;
|
||||
frame = [_view convertRectToBacking:[_view frame]];
|
||||
container = [_view convertRectToBacking:[[_view superview] frame]];
|
||||
} else {
|
||||
frame = [_window contentRectForFrameRect:[_window frame]];
|
||||
x = frame.origin.x;
|
||||
y = [[_window screen] frame].size.height - frame.origin.y - frame.size.height;
|
||||
frame = [_view convertRectToBacking:[_window contentRectForFrameRect:[_window frame]]];
|
||||
NSScreen *screen = [_window screen];
|
||||
nassertv(screen != nil);
|
||||
container = [_view convertRectToBacking:[screen frame]];
|
||||
}
|
||||
|
||||
// Y coordinate in backing store is not flipped, but origin is still at the bottom left
|
||||
x = frame.origin.x;
|
||||
y = container.size.height + frame.origin.y;
|
||||
|
||||
if (x != _properties.get_x_origin() ||
|
||||
y != _properties.get_y_origin()) {
|
||||
|
||||
|
|
@ -1290,7 +1369,7 @@ handle_resize_event() {
|
|||
[_view setFrameSize:contentRect.size];
|
||||
}
|
||||
|
||||
NSRect frame = [_view convertRect:[_view bounds] toView:nil];
|
||||
NSRect frame = [_view convertRectToBacking:[_view bounds]];
|
||||
|
||||
WindowProperties properties;
|
||||
bool changed = false;
|
||||
|
|
@ -1403,6 +1482,22 @@ handle_foreground_event(bool foreground) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called by the window delegate when the properties of backing store of the
|
||||
* window have changed.
|
||||
*/
|
||||
void CocoaGraphicsWindow::
|
||||
handle_backing_change_event() {
|
||||
if (cocoadisplay_cat.is_debug()) {
|
||||
cocoadisplay_cat.debug() << "Backing store properties have changed\n";
|
||||
}
|
||||
// Trigger a resize event to update the window size in case the backing scale
|
||||
// factor did change.
|
||||
handle_resize_event();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called by the window delegate when the user requests to close the window.
|
||||
* This may not always be called, which is why there is also a
|
||||
|
|
@ -1693,6 +1788,13 @@ void CocoaGraphicsWindow::
|
|||
handle_mouse_moved_event(bool in_window, double x, double y, bool absolute) {
|
||||
double nx, ny;
|
||||
|
||||
// Mouse position is received in screen points and not pixels, but in Panda3D
|
||||
// we want to have the coordinates expressed in pixels.
|
||||
// Instead of using convertPointFrom/toBackingStore and have complex logic to
|
||||
// cope with the change of coordinate system, we cheat and directly use the
|
||||
// contents scale of the view layer to convert screen point into pixels and
|
||||
// vice-versa.
|
||||
CGFloat contents_scale = _view.layer.contentsScale;
|
||||
if (absolute) {
|
||||
if (cocoadisplay_cat.is_spam()) {
|
||||
if (in_window != _input->get_pointer().get_in_window()) {
|
||||
|
|
@ -1704,14 +1806,14 @@ handle_mouse_moved_event(bool in_window, double x, double y, bool absolute) {
|
|||
}
|
||||
}
|
||||
|
||||
nx = x;
|
||||
ny = y;
|
||||
nx = x * contents_scale;
|
||||
ny = y * contents_scale;
|
||||
|
||||
} else {
|
||||
// We received deltas, so add it to the current mouse position.
|
||||
PointerData md = _input->get_pointer();
|
||||
nx = md.get_x() + x;
|
||||
ny = md.get_y() + y;
|
||||
nx = md.get_x() + x * contents_scale;
|
||||
ny = md.get_y() + y * contents_scale;
|
||||
}
|
||||
|
||||
if (_properties.get_mouse_mode() == WindowProperties::M_confined
|
||||
|
|
@ -1721,11 +1823,13 @@ handle_mouse_moved_event(bool in_window, double x, double y, bool absolute) {
|
|||
nx = std::max(0., std::min((double) get_x_size() - 1, nx));
|
||||
ny = std::max(0., std::min((double) get_y_size() - 1, ny));
|
||||
|
||||
// Convert back mouse position to screen space using point units
|
||||
if (_properties.get_fullscreen()) {
|
||||
point = CGPointMake(nx, ny);
|
||||
point = CGPointMake(nx / contents_scale,
|
||||
ny / contents_scale);
|
||||
} else {
|
||||
point = CGPointMake(nx + _properties.get_x_origin(),
|
||||
ny + _properties.get_y_origin());
|
||||
point = CGPointMake((nx + _properties.get_x_origin()) / contents_scale,
|
||||
(ny + _properties.get_y_origin()) / contents_scale);
|
||||
}
|
||||
|
||||
if (CGWarpMouseCursorPosition(point) == kCGErrorSuccess) {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ class CocoaGraphicsWindow;
|
|||
- (void)windowDidDeminiaturize:(NSNotification *)notification;
|
||||
- (void)windowDidBecomeKey:(NSNotification *)notification;
|
||||
- (void)windowDidResignKey:(NSNotification *)notification;
|
||||
- (void)windowDidChangeBackingProperties:(NSNotification *)notification;
|
||||
- (BOOL)windowShouldClose:(id)sender;
|
||||
- (void)windowWillClose:(id)sender;
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@
|
|||
_graphicsWindow->handle_foreground_event(false);
|
||||
}
|
||||
|
||||
- (void) windowDidChangeBackingProperties:(NSNotification *)notification {
|
||||
_graphicsWindow->handle_backing_change_event();
|
||||
}
|
||||
|
||||
- (BOOL) windowShouldClose:(id)sender {
|
||||
if (cocoadisplay_cat.is_debug()) {
|
||||
cocoadisplay_cat.debug()
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
NotifyCategoryDecl(cocoadisplay, EXPCL_PANDA_COCOADISPLAY, EXPTP_PANDA_COCOADISPLAY);
|
||||
|
||||
extern ConfigVariableBool cocoa_invert_wheel_x;
|
||||
extern ConfigVariableBool dpi_aware;
|
||||
|
||||
extern EXPCL_PANDA_COCOADISPLAY void init_libcocoadisplay();
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,11 @@ ConfigVariableBool cocoa_invert_wheel_x
|
|||
("cocoa-invert-wheel-x", false,
|
||||
PRC_DESC("Set this to true to swap the wheel_left and wheel_right mouse "
|
||||
"button events, to restore to the pre-1.10.12 behavior."));
|
||||
ConfigVariableBool dpi_aware
|
||||
("dpi-aware", false,
|
||||
PRC_DESC("The default behavior on macOS is for Panda3D to use upscaling on"
|
||||
"high DPI screen. Set this to true to let the application use the"
|
||||
"actual pixel density of the screen."));
|
||||
|
||||
/**
|
||||
* Initializes the library. This must be called at least once before any of
|
||||
|
|
|
|||
|
|
@ -64,6 +64,11 @@
|
|||
|
||||
using std::string;
|
||||
|
||||
static const LMatrix4 shadow_bias_mat(0.5f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.5f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.5f, 0.0f,
|
||||
0.5f, 0.5f, 0.5f, 1.0f);
|
||||
|
||||
//PStatCollector GraphicsStateGuardian::_vertex_buffer_switch_pcollector("Buffer switch:Vertex");
|
||||
//PStatCollector GraphicsStateGuardian::_index_buffer_switch_pcollector("Buffer switch:Index");
|
||||
//PStatCollector GraphicsStateGuardian::_shader_buffer_switch_pcollector("Buffer switch:Shader");
|
||||
|
|
@ -1543,9 +1548,30 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
|
|||
}
|
||||
|
||||
const NodePath &np = _target_shader->get_shader_input_nodepath(name->get_parent());
|
||||
nassertv(!np.is_empty());
|
||||
const PandaNode *node = np.node();
|
||||
|
||||
fetch_specified_member(np, name->get_basename(), into[0]);
|
||||
// This is the only matrix member we support from NodePath inputs.
|
||||
if (node != nullptr && node->is_of_type(LensNode::get_class_type()) &&
|
||||
name->get_basename() == "shadowViewMatrix") {
|
||||
const LensNode *lnode = (const LensNode *)node;
|
||||
const Lens *lens = lnode->get_lens();
|
||||
|
||||
LMatrix4 t = _inv_cs_transform->get_mat() *
|
||||
_scene_setup->get_camera_transform()->get_mat() *
|
||||
np.get_net_transform()->get_inverse()->get_mat() *
|
||||
LMatrix4::convert_mat(_coordinate_system, lens->get_coordinate_system());
|
||||
|
||||
if (!lnode->is_of_type(PointLight::get_class_type())) {
|
||||
t *= lens->get_projection_mat() * shadow_bias_mat;
|
||||
}
|
||||
*(LMatrix4f *)into = LCAST(float, t);
|
||||
}
|
||||
else {
|
||||
display_cat.error()
|
||||
<< "Shader input " << *name << " requests invalid attribute "
|
||||
<< name->get_basename() << " from node " << np << "\n";
|
||||
*(LMatrix4f *)into = LMatrix4f::ident_mat();
|
||||
}
|
||||
return;
|
||||
}
|
||||
case Shader::SMO_vec_constant_x_attrib: {
|
||||
|
|
@ -1588,12 +1614,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
|
|||
}
|
||||
return;
|
||||
}
|
||||
case Shader::SMO_apiview_to_apiclip_light_source_i: {
|
||||
static const LMatrix4 biasmat(0.5f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.5f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.5f, 0.0f,
|
||||
0.5f, 0.5f, 0.5f, 1.0f);
|
||||
|
||||
case Shader::SMO_apiview_to_apiclip_light_source_i: { // shadowViewMatrix
|
||||
const LightAttrib *target_light;
|
||||
_target_rs->get_attrib_def(target_light);
|
||||
|
||||
|
|
@ -1616,14 +1637,14 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
|
|||
LMatrix4::convert_mat(_coordinate_system, lens->get_coordinate_system());
|
||||
|
||||
if (!lnode->is_of_type(PointLight::get_class_type())) {
|
||||
t *= lens->get_projection_mat() * biasmat;
|
||||
t *= lens->get_projection_mat() * shadow_bias_mat;
|
||||
}
|
||||
((LMatrix4f *)into)[i] = LCAST(float, t);
|
||||
}
|
||||
|
||||
// Apply just the bias matrix otherwise.
|
||||
for (; i < (size_t)count; ++i) {
|
||||
((LMatrix4f *)into)[i] = LCAST(float, biasmat);
|
||||
((LMatrix4f *)into)[i] = LCAST(float, shadow_bias_mat);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1570,8 +1570,8 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
|
|||
bind._func = Shader::SMF_compose;
|
||||
bind._part[0] = Shader::SMO_model_to_apiview;
|
||||
bind._arg[0] = nullptr;
|
||||
bind._part[1] = Shader::SMO_apiview_to_apiclip_light_source_i;
|
||||
bind._arg[1] = nullptr;
|
||||
bind._part[1] = Shader::SMO_mat_constant_x_attrib;
|
||||
bind._arg[1] = iname->get_parent()->append("shadowViewMatrix");
|
||||
} else {
|
||||
bind._part[0] = Shader::SMO_mat_constant_x_attrib;
|
||||
bind._arg[0] = InternalName::make(param_name);
|
||||
|
|
|
|||
|
|
@ -215,19 +215,24 @@ is_prepared(PreparedGraphicsObjects *prepared_objects) const {
|
|||
VertexBufferContext *GeomVertexArrayData::
|
||||
prepare_now(PreparedGraphicsObjects *prepared_objects,
|
||||
GraphicsStateGuardianBase *gsg) {
|
||||
if (_contexts == nullptr) {
|
||||
if (_contexts != nullptr) {
|
||||
Contexts::const_iterator ci;
|
||||
ci = _contexts->find(prepared_objects);
|
||||
if (ci != _contexts->end()) {
|
||||
return (*ci).second;
|
||||
}
|
||||
} else {
|
||||
_contexts = new Contexts;
|
||||
}
|
||||
Contexts::const_iterator ci;
|
||||
ci = _contexts->find(prepared_objects);
|
||||
if (ci != _contexts->end()) {
|
||||
return (*ci).second;
|
||||
}
|
||||
|
||||
VertexBufferContext *vbc = prepared_objects->prepare_vertex_buffer_now(this, gsg);
|
||||
if (vbc != nullptr) {
|
||||
(*_contexts)[prepared_objects] = vbc;
|
||||
}
|
||||
else if (_contexts->empty()) {
|
||||
delete _contexts;
|
||||
_contexts = nullptr;
|
||||
}
|
||||
return vbc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -652,7 +652,6 @@ cp_add_mat_spec(ShaderMatSpec &spec) {
|
|||
case SMO_pixel_size:
|
||||
case SMO_texpad_x:
|
||||
case SMO_texpix_x:
|
||||
case SMO_attr_material:
|
||||
case SMO_attr_color:
|
||||
case SMO_attr_colorscale:
|
||||
case SMO_satten_x:
|
||||
|
|
@ -684,6 +683,7 @@ cp_add_mat_spec(ShaderMatSpec &spec) {
|
|||
break;
|
||||
|
||||
case SMO_identity:
|
||||
case SMO_attr_material:
|
||||
case SMO_alight_x:
|
||||
case SMO_dlight_x:
|
||||
case SMO_plight_x:
|
||||
|
|
|
|||
|
|
@ -76,19 +76,24 @@ is_prepared(PreparedGraphicsObjects *prepared_objects) const {
|
|||
BufferContext *ShaderBuffer::
|
||||
prepare_now(PreparedGraphicsObjects *prepared_objects,
|
||||
GraphicsStateGuardianBase *gsg) {
|
||||
if (_contexts == nullptr) {
|
||||
if (_contexts != nullptr) {
|
||||
Contexts::const_iterator ci;
|
||||
ci = _contexts->find(prepared_objects);
|
||||
if (ci != _contexts->end()) {
|
||||
return (*ci).second;
|
||||
}
|
||||
} else {
|
||||
_contexts = new Contexts;
|
||||
}
|
||||
Contexts::const_iterator ci;
|
||||
ci = _contexts->find(prepared_objects);
|
||||
if (ci != _contexts->end()) {
|
||||
return (*ci).second;
|
||||
}
|
||||
|
||||
BufferContext *vbc = prepared_objects->prepare_shader_buffer_now(this, gsg);
|
||||
if (vbc != nullptr) {
|
||||
(*_contexts)[prepared_objects] = vbc;
|
||||
}
|
||||
else if (_contexts->empty()) {
|
||||
delete _contexts;
|
||||
_contexts = nullptr;
|
||||
}
|
||||
return vbc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,19 +92,7 @@ BMPlenrgbtable(int classv, unsigned long bitcount)
|
|||
pm_error(er_internal, "BMPlenrgbtable");
|
||||
return 0;
|
||||
}
|
||||
switch (classv)
|
||||
{
|
||||
case C_WIN:
|
||||
lenrgb = 4;
|
||||
break;
|
||||
case C_OS2:
|
||||
lenrgb = 3;
|
||||
break;
|
||||
default:
|
||||
pm_error(er_internal, "BMPlenrgbtable");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lenrgb = (classv == C_OS2) ? 3 : 4;
|
||||
return (1 << bitcount) * lenrgb;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ public:
|
|||
unsigned long offBits;
|
||||
|
||||
unsigned short cBitCount;
|
||||
unsigned short cCompression;
|
||||
int indexed;
|
||||
int classv;
|
||||
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ BMPreadinfoheader(
|
|||
unsigned long *pcx,
|
||||
unsigned long *pcy,
|
||||
unsigned short *pcBitCount,
|
||||
unsigned short *pcCompression,
|
||||
int *pclassv)
|
||||
{
|
||||
unsigned long cbFix;
|
||||
|
|
@ -185,6 +186,7 @@ BMPreadinfoheader(
|
|||
unsigned long cx = 0;
|
||||
unsigned long cy = 0;
|
||||
unsigned short cBitCount = 0;
|
||||
unsigned long cCompression = 0;
|
||||
int classv = 0;
|
||||
|
||||
cbFix = GetLong(fp);
|
||||
|
|
@ -229,7 +231,9 @@ BMPreadinfoheader(
|
|||
* for the required total.
|
||||
*/
|
||||
if (classv != C_OS2) {
|
||||
for (int i = 0; i < (int)cbFix - 16; i += 4) {
|
||||
cCompression = GetLong(fp);
|
||||
|
||||
for (int i = 0; i < (int)cbFix - 20; i += 4) {
|
||||
GetLong(fp);
|
||||
}
|
||||
}
|
||||
|
|
@ -273,11 +277,13 @@ BMPreadinfoheader(
|
|||
pm_message("cy: %d", cy);
|
||||
pm_message("cPlanes: %d", cPlanes);
|
||||
pm_message("cBitCount: %d", cBitCount);
|
||||
pm_message("cCompression: %d", cCompression);
|
||||
#endif
|
||||
|
||||
*pcx = cx;
|
||||
*pcy = cy;
|
||||
*pcBitCount = cBitCount;
|
||||
*pcCompression = cCompression;
|
||||
*pclassv = classv;
|
||||
|
||||
*ppos += cbFix;
|
||||
|
|
@ -401,45 +407,84 @@ BMPreadbits(xel *array, xelval *alpha_array,
|
|||
unsigned long cx,
|
||||
unsigned long cy,
|
||||
unsigned short cBitCount,
|
||||
int /* classv */,
|
||||
unsigned long cCompression,
|
||||
int indexed,
|
||||
pixval *R,
|
||||
pixval *G,
|
||||
pixval *B)
|
||||
{
|
||||
long y;
|
||||
long y;
|
||||
|
||||
readto(fp, ppos, offBits);
|
||||
readto(fp, ppos, offBits);
|
||||
|
||||
if(cBitCount > 24 && cBitCount != 32)
|
||||
{
|
||||
pm_error("%s: cannot handle cBitCount: %d"
|
||||
,ifname
|
||||
,cBitCount);
|
||||
if (cBitCount > 24 && cBitCount != 32) {
|
||||
pm_error("%s: cannot handle cBitCount: %d", ifname, cBitCount);
|
||||
}
|
||||
|
||||
if (cCompression == 1) {
|
||||
// RLE8 compression
|
||||
xel *row = array + (cy - 1) * cx;
|
||||
xel *p = row;
|
||||
unsigned long nbyte = 0;
|
||||
while (true) {
|
||||
int first = GetByte(fp);
|
||||
int second = GetByte(fp);
|
||||
nbyte += 2;
|
||||
|
||||
if (first != 0) {
|
||||
// Repeated index.
|
||||
for (int i = 0; i < first; ++i) {
|
||||
PPM_ASSIGN(*p, R[second], G[second], B[second]);
|
||||
++p;
|
||||
}
|
||||
|
||||
/*
|
||||
* The picture is stored bottom line first, top line last
|
||||
*/
|
||||
|
||||
for (y = (long)cy - 1; y >= 0; y--)
|
||||
{
|
||||
int rc;
|
||||
rc = BMPreadrow(fp, ppos, array + y*cx, alpha_array + y*cx, cx, cBitCount, indexed, R, G, B);
|
||||
if(rc == -1)
|
||||
{
|
||||
pm_error("%s: couldn't read row %d"
|
||||
,ifname
|
||||
,y);
|
||||
}
|
||||
if(rc%4)
|
||||
{
|
||||
pm_error("%s: row had bad number of bytes: %d"
|
||||
,ifname
|
||||
,rc);
|
||||
}
|
||||
}
|
||||
else if (second == 0) {
|
||||
// End of line.
|
||||
row -= cx;
|
||||
p = row;
|
||||
}
|
||||
else if (second == 1) {
|
||||
// End of image.
|
||||
break;
|
||||
}
|
||||
else if (second == 2) {
|
||||
// Delta.
|
||||
int xoffset = GetByte(fp);
|
||||
int yoffset = GetByte(fp);
|
||||
nbyte += 2;
|
||||
row -= cx * yoffset;
|
||||
p += xoffset - cx * yoffset;
|
||||
}
|
||||
else {
|
||||
// Absolute run.
|
||||
for (int i = 0; i < second; ++i) {
|
||||
int v = GetByte(fp);
|
||||
++nbyte;
|
||||
PPM_ASSIGN(*p, R[v], G[v], B[v]);
|
||||
++p;
|
||||
}
|
||||
|
||||
nbyte += second;
|
||||
if (second % 2) {
|
||||
// Pad to 16-bit boundary.
|
||||
GetByte(fp);
|
||||
++nbyte;
|
||||
}
|
||||
}
|
||||
}
|
||||
*ppos += nbyte;
|
||||
}
|
||||
else {
|
||||
// The picture is stored bottom line first, top line last
|
||||
for (y = (long)cy - 1; y >= 0; y--) {
|
||||
int rc = BMPreadrow(fp, ppos, array + y*cx, alpha_array + y*cx, cx, cBitCount, indexed, R, G, B);
|
||||
if (rc == -1) {
|
||||
pm_error("%s: couldn't read row %d", ifname, y);
|
||||
}
|
||||
if (rc % 4) {
|
||||
pm_error("%s: row had bad number of bytes: %d", ifname, rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -474,7 +519,7 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
|
|||
pos = 0;
|
||||
|
||||
BMPreadfileheader(file, &pos, &offBits);
|
||||
BMPreadinfoheader(file, &pos, &cx, &cy, &cBitCount, &classv);
|
||||
BMPreadinfoheader(file, &pos, &cx, &cy, &cBitCount, &cCompression, &classv);
|
||||
|
||||
if (offBits != BMPoffbits(classv, cBitCount)) {
|
||||
pnmimage_bmp_cat.warning()
|
||||
|
|
@ -523,9 +568,10 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
|
|||
int PNMFileTypeBMP::Reader::
|
||||
read_data(xel *array, xelval *alpha_array) {
|
||||
BMPreadbits(array, alpha_array, _file, &pos, offBits, _x_size, _y_size,
|
||||
cBitCount, classv, indexed, R, G, B);
|
||||
cBitCount, cCompression, indexed, R, G, B);
|
||||
|
||||
if (pos != BMPlenfile(classv, cBitCount, _x_size, _y_size)) {
|
||||
if (cCompression != 1 &&
|
||||
pos != BMPlenfile(classv, cBitCount, _x_size, _y_size)) {
|
||||
pnmimage_bmp_cat.warning()
|
||||
<< "Read " << pos << " bytes, expected to read "
|
||||
<< BMPlenfile(classv, cBitCount, _x_size, _y_size) << " bytes\n";
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
*/
|
||||
void Extension<BitArray>::
|
||||
__init__(PyObject *init_value) {
|
||||
if (!PyLong_Check(init_value) || Py_SIZE(init_value) < 0) {
|
||||
if (!PyLong_Check(init_value) || !PyLong_IsNonNegative(init_value)) {
|
||||
PyErr_SetString(PyExc_ValueError, "BitArray constructor requires a positive integer");
|
||||
return;
|
||||
}
|
||||
|
|
@ -76,7 +76,7 @@ __getstate__() const {
|
|||
*/
|
||||
void Extension<BitArray>::
|
||||
__setstate__(PyObject *state) {
|
||||
if (Py_SIZE(state) >= 0) {
|
||||
if (PyLong_IsNonNegative(state)) {
|
||||
__init__(state);
|
||||
} else {
|
||||
PyObject *inverted = PyNumber_Invert(state);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
template<class BMType>
|
||||
INLINE void Extension<DoubleBitMask<BMType> >::
|
||||
__init__(PyObject *init_value) {
|
||||
if (!PyLong_Check(init_value) || Py_SIZE(init_value) < 0) {
|
||||
if (!PyLong_Check(init_value) || !PyLong_IsNonNegative(init_value)) {
|
||||
PyErr_SetString(PyExc_ValueError, "DoubleBitMask constructor requires a positive integer");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
import pytest
|
||||
from panda3d import core
|
||||
from direct.directnotify import DirectNotify, Logger, Notifier
|
||||
|
||||
CATEGORY_NAME = 'test'
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def notify():
|
||||
notify = DirectNotify.DirectNotify()
|
||||
notify.newCategory(CATEGORY_NAME)
|
||||
return notify
|
||||
|
||||
|
||||
def test_categories():
|
||||
notify = DirectNotify.DirectNotify()
|
||||
assert len(notify.getCategories()) == 0
|
||||
assert notify.getCategory(CATEGORY_NAME) is None
|
||||
notifier = notify.newCategory(CATEGORY_NAME, logger=Logger.Logger())
|
||||
assert isinstance(notifier, Notifier.Notifier)
|
||||
assert notify.getCategories() == [CATEGORY_NAME]
|
||||
|
||||
|
||||
def test_setDconfigLevels(notify):
|
||||
config = core.ConfigVariableString('notify-level-' + CATEGORY_NAME, '')
|
||||
notifier = notify.getCategory(CATEGORY_NAME)
|
||||
config.value = 'error'
|
||||
notify.setDconfigLevels()
|
||||
assert notifier.getSeverity() == core.NS_error
|
||||
config.value = 'warning'
|
||||
notify.setDconfigLevels()
|
||||
assert notifier.getSeverity() == core.NS_warning
|
||||
config.value = 'info'
|
||||
notify.setDconfigLevels()
|
||||
assert notifier.getSeverity() == core.NS_info
|
||||
config.value = 'debug'
|
||||
notify.setDconfigLevels()
|
||||
assert notifier.getSeverity() == core.NS_debug
|
||||
|
||||
|
||||
def test_setVerbose(notify):
|
||||
notifier = notify.getCategory(CATEGORY_NAME)
|
||||
notifier.setWarning(False)
|
||||
notifier.setInfo(False)
|
||||
notifier.setDebug(False)
|
||||
notify.setVerbose()
|
||||
assert notifier.getWarning()
|
||||
assert notifier.getInfo()
|
||||
assert notifier.getDebug()
|
||||
|
||||
|
||||
def test_giveNotify(notify):
|
||||
class HasNotify:
|
||||
notify = None
|
||||
|
||||
notify.giveNotify(HasNotify)
|
||||
assert isinstance(HasNotify.notify, Notifier.Notifier)
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import re
|
||||
from direct.directnotify import Logger
|
||||
|
||||
LOG_TEXT = 'Arbitrary log text'
|
||||
|
||||
|
||||
def test_logging(tmp_path):
|
||||
log_filename = str(tmp_path / 'log')
|
||||
logger = Logger.Logger(log_filename)
|
||||
|
||||
assert logger.getTimeStamp()
|
||||
logger.log(LOG_TEXT)
|
||||
logger.setTimeStamp(False)
|
||||
assert not logger.getTimeStamp()
|
||||
logger.log(LOG_TEXT)
|
||||
logger._Logger__closeLogFile()
|
||||
|
||||
log_file, = tmp_path.iterdir()
|
||||
log_text = log_file.read_text()
|
||||
pattern = rf'\d\d:\d\d:\d\d:\d\d: {LOG_TEXT}\n{LOG_TEXT}\n'
|
||||
assert re.match(pattern, log_text)
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
import io
|
||||
import re
|
||||
import time
|
||||
import pytest
|
||||
from panda3d import core
|
||||
from direct.directnotify import Logger, Notifier
|
||||
|
||||
NOTIFIER_NAME = 'Test notifier'
|
||||
DEBUG_LOG = 'Debug log'
|
||||
INFO_LOG = 'Info log'
|
||||
WARNING_LOG = 'Warning log'
|
||||
ERROR_LOG = 'Error log'
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def log_io():
|
||||
return io.StringIO()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def notifier(log_io):
|
||||
logger = Logger.Logger()
|
||||
logger.setTimeStamp(False)
|
||||
logger._Logger__logFile = log_io
|
||||
notifier = Notifier.Notifier(NOTIFIER_NAME, logger)
|
||||
notifier.setLogging(True)
|
||||
return notifier
|
||||
|
||||
|
||||
def test_setServerDelta():
|
||||
notifier = Notifier.Notifier(NOTIFIER_NAME)
|
||||
notifier.setServerDelta(4.2, time.timezone)
|
||||
assert Notifier.Notifier.serverDelta == 4
|
||||
Notifier.Notifier.serverDelta = 0
|
||||
|
||||
|
||||
def test_logging(notifier, log_io):
|
||||
notifier.setLogging(False)
|
||||
assert not notifier.getLogging()
|
||||
notifier.info(INFO_LOG)
|
||||
assert log_io.getvalue() == ''
|
||||
|
||||
notifier.setLogging(True)
|
||||
assert notifier.getLogging()
|
||||
notifier.info(INFO_LOG)
|
||||
assert log_io.getvalue() == f':{NOTIFIER_NAME}: {INFO_LOG}\n'
|
||||
|
||||
|
||||
@pytest.mark.parametrize('severity', (core.NS_debug, core.NS_info, core.NS_warning, core.NS_error))
|
||||
def test_severity(severity, notifier, log_io):
|
||||
notifier.setSeverity(severity)
|
||||
assert notifier.getSeverity() == severity
|
||||
|
||||
with pytest.raises(Notifier.NotifierException):
|
||||
notifier.error(ERROR_LOG)
|
||||
warning_return = notifier.warning(WARNING_LOG)
|
||||
info_return = notifier.info(INFO_LOG)
|
||||
debug_return = notifier.debug(DEBUG_LOG)
|
||||
assert warning_return and info_return and debug_return
|
||||
|
||||
expected_logs = [
|
||||
f'{Notifier.NotifierException}: {NOTIFIER_NAME}(error): {ERROR_LOG}',
|
||||
f':{NOTIFIER_NAME}(warning): {WARNING_LOG}',
|
||||
f':{NOTIFIER_NAME}: {INFO_LOG}',
|
||||
f':{NOTIFIER_NAME}(debug): {DEBUG_LOG}',
|
||||
]
|
||||
del expected_logs[6-severity:]
|
||||
assert log_io.getvalue() == '\n'.join(expected_logs) + '\n'
|
||||
|
||||
|
||||
def test_custom_exception(notifier):
|
||||
class CustomException(Exception):
|
||||
pass
|
||||
|
||||
with pytest.raises(CustomException):
|
||||
notifier.error(ERROR_LOG, CustomException)
|
||||
|
||||
|
||||
def test_debugCall(notifier, log_io):
|
||||
notifier.setDebug(False)
|
||||
return_value = notifier.debugCall(DEBUG_LOG)
|
||||
assert return_value
|
||||
assert log_io.getvalue() == ''
|
||||
notifier.setDebug(True)
|
||||
notifier.debugCall(DEBUG_LOG)
|
||||
pattern = rf':\d\d:\d\d:\d\d:{NOTIFIER_NAME} "{DEBUG_LOG}" test_debugCall\(.*\)\n'
|
||||
assert re.match(pattern, log_io.getvalue())
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
import pytest
|
||||
from direct.directnotify import RotatingLog
|
||||
|
||||
LOG_TEXT = 'Arbitrary log text'
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def log_dir(tmp_path):
|
||||
log_dir = tmp_path / 'logs'
|
||||
log_dir.mkdir()
|
||||
return log_dir
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def rotating_log(log_dir):
|
||||
log_filename = str(log_dir / 'log')
|
||||
rotating_log = RotatingLog.RotatingLog(log_filename)
|
||||
yield rotating_log
|
||||
rotating_log.close()
|
||||
|
||||
|
||||
def test_rotation(rotating_log, log_dir):
|
||||
rotating_log.sizeLimit = -1
|
||||
rotating_log.write('1')
|
||||
rotating_log.write('2')
|
||||
written = [f.read_text() for f in log_dir.iterdir()]
|
||||
assert written == ['1', '2'] or written == ['2', '1']
|
||||
|
||||
|
||||
def test_wrapper_methods(rotating_log, log_dir):
|
||||
rotating_log.write('')
|
||||
log_file, = log_dir.iterdir()
|
||||
|
||||
assert rotating_log.fileno() == rotating_log.file.fileno()
|
||||
assert rotating_log.isatty() == rotating_log.file.isatty()
|
||||
|
||||
rotating_log.writelines([LOG_TEXT] * 10)
|
||||
assert not log_file.read_text()
|
||||
rotating_log.flush()
|
||||
assert log_file.read_text() == LOG_TEXT * 10
|
||||
|
||||
assert rotating_log.tell() == len(LOG_TEXT) * 10
|
||||
rotating_log.seek(len(LOG_TEXT))
|
||||
rotating_log.truncate(None)
|
||||
assert log_file.read_text() == LOG_TEXT
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
import os
|
||||
import platform
|
||||
import pytest
|
||||
|
||||
from panda3d import core
|
||||
|
||||
|
|
@ -16,12 +18,14 @@ def run_cg_compile_check(gsg, shader_path, expect_fail=False):
|
|||
assert shader is not None
|
||||
|
||||
|
||||
@pytest.mark.skipif(platform.machine().lower() == 'arm64', reason="Cg not supported on arm64")
|
||||
def test_cg_compile_error(gsg):
|
||||
"""Test getting compile errors from bad Cg shaders"""
|
||||
shader_path = core.Filename(SHADERS_DIR, 'cg_bad.sha')
|
||||
run_cg_compile_check(gsg, shader_path, expect_fail=True)
|
||||
|
||||
|
||||
@pytest.mark.skipif(platform.machine().lower() == 'arm64', reason="Cg not supported on arm64")
|
||||
def test_cg_from_file(gsg):
|
||||
"""Test compiling Cg shaders from files"""
|
||||
shader_path = core.Filename(SHADERS_DIR, 'cg_simple.sha')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
from direct.dist.FreezeTool import Freezer, PandaModuleFinder
|
||||
import sys
|
||||
|
||||
|
||||
def test_Freezer_moduleSuffixes():
|
||||
freezer = Freezer()
|
||||
|
||||
for suffix, mode, type in freezer.mf.suffixes:
|
||||
if type == 2: # imp.PY_SOURCE
|
||||
assert mode == 'rb'
|
||||
|
||||
|
||||
def test_Freezer_getModulePath_getModuleStar(tmp_path):
|
||||
# Package 1 can be imported
|
||||
package1 = tmp_path / "package1"
|
||||
package1.mkdir()
|
||||
(package1 / "submodule1.py").write_text("")
|
||||
(package1 / "__init__.py").write_text("")
|
||||
|
||||
# Package 2 can not be imported
|
||||
package2 = tmp_path / "package2"
|
||||
package2.mkdir()
|
||||
(package2 / "submodule2.py").write_text("")
|
||||
(package2 / "__init__.py").write_text("raise ImportError\n")
|
||||
|
||||
# Module 1 can be imported
|
||||
(tmp_path / "module1.py").write_text("")
|
||||
|
||||
# Module 2 can not be imported
|
||||
(tmp_path / "module2.py").write_text("raise ImportError\n")
|
||||
|
||||
backup = sys.path
|
||||
try:
|
||||
# Don't fail if first item on path does not exist
|
||||
sys.path = [str(tmp_path / "nonexistent"), str(tmp_path)]
|
||||
|
||||
freezer = Freezer()
|
||||
assert freezer.getModulePath("nonexist") == None
|
||||
assert freezer.getModulePath("package1") == [str(package1)]
|
||||
assert freezer.getModulePath("package2") == [str(package2)]
|
||||
assert freezer.getModulePath("package1.submodule1") == None
|
||||
assert freezer.getModulePath("package1.nonexist") == None
|
||||
assert freezer.getModulePath("package2.submodule2") == None
|
||||
assert freezer.getModulePath("package2.nonexist") == None
|
||||
assert freezer.getModulePath("module1") == None
|
||||
assert freezer.getModulePath("module2") == None
|
||||
|
||||
assert freezer.getModuleStar("nonexist") == None
|
||||
assert freezer.getModuleStar("package1") == ['submodule1']
|
||||
assert freezer.getModuleStar("package2") == ['submodule2']
|
||||
assert freezer.getModuleStar("package1.submodule1") == None
|
||||
assert freezer.getModuleStar("package1.nonexist") == None
|
||||
assert freezer.getModuleStar("package2.submodule2") == None
|
||||
assert freezer.getModuleStar("package2.nonexist") == None
|
||||
assert freezer.getModuleStar("module1") == None
|
||||
assert freezer.getModuleStar("module2") == None
|
||||
finally:
|
||||
sys.path = backup
|
||||
|
|
@ -118,6 +118,9 @@ def test_bitarray_pickle():
|
|||
ba = BitArray(123)
|
||||
assert ba == pickle.loads(pickle.dumps(ba, -1))
|
||||
|
||||
ba = BitArray(1 << 128)
|
||||
assert ba == pickle.loads(pickle.dumps(ba, -1))
|
||||
|
||||
ba = BitArray(94187049178237918273981729127381723)
|
||||
assert ba == pickle.loads(pickle.dumps(ba, -1))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +1,82 @@
|
|||
import pytest
|
||||
from panda3d import core
|
||||
from direct.task import Task
|
||||
|
||||
|
||||
def test_TaskManager():
|
||||
tm = Task.TaskManager()
|
||||
tm.mgr = core.AsyncTaskManager("Test manager")
|
||||
tm.setClock(core.ClockObject())
|
||||
tm.setupTaskChain("default", tickClock = True)
|
||||
TASK_NAME = 'Arbitrary task name'
|
||||
TASK_CHAIN_NAME = 'Arbitrary task chain name'
|
||||
|
||||
tm._startTrackingMemLeaks = lambda: None
|
||||
tm._stopTrackingMemLeaks = lambda: None
|
||||
tm._checkMemLeaks = lambda: None
|
||||
|
||||
# check for memory leaks after every test
|
||||
tm._startTrackingMemLeaks()
|
||||
tm._checkMemLeaks()
|
||||
def DUMMY_FUNCTION(*_):
|
||||
pass
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def task_manager():
|
||||
manager = Task.TaskManager()
|
||||
manager.mgr = core.AsyncTaskManager('Test manager')
|
||||
manager.clock = core.ClockObject()
|
||||
manager.setupTaskChain('default', tickClock=True)
|
||||
manager.finalInit()
|
||||
yield manager
|
||||
manager.destroy()
|
||||
|
||||
|
||||
def test_sequence(task_manager):
|
||||
numbers = []
|
||||
|
||||
def append_1(task):
|
||||
numbers.append(1)
|
||||
|
||||
def append_2(task):
|
||||
numbers.append(2)
|
||||
|
||||
sequence = Task.sequence(core.PythonTask(append_1), core.PythonTask(append_2))
|
||||
task_manager.add(sequence)
|
||||
for _ in range(3):
|
||||
task_manager.step()
|
||||
assert not task_manager.getTasks()
|
||||
assert numbers == [1, 2]
|
||||
|
||||
|
||||
def test_loop(task_manager):
|
||||
numbers = []
|
||||
|
||||
def append_1(task):
|
||||
numbers.append(1)
|
||||
|
||||
def append_2(task):
|
||||
numbers.append(2)
|
||||
|
||||
loop = Task.loop(core.PythonTask(append_1), core.PythonTask(append_2))
|
||||
task_manager.add(loop)
|
||||
for _ in range(5):
|
||||
task_manager.step()
|
||||
assert numbers == [1, 2, 1, 2]
|
||||
|
||||
|
||||
def test_get_current_task(task_manager):
|
||||
def check_current_task(task):
|
||||
assert task_manager.getCurrentTask().name == TASK_NAME
|
||||
|
||||
task_manager.add(check_current_task, TASK_NAME)
|
||||
assert len(task_manager.getTasks()) == 1
|
||||
assert task_manager.getCurrentTask() is None
|
||||
|
||||
task_manager.step()
|
||||
assert len(task_manager.getTasks()) == 0
|
||||
assert task_manager.getCurrentTask() is None
|
||||
|
||||
|
||||
def test_has_task_chain(task_manager):
|
||||
assert not task_manager.hasTaskChain(TASK_CHAIN_NAME)
|
||||
task_manager.setupTaskChain(TASK_CHAIN_NAME)
|
||||
assert task_manager.hasTaskChain(TASK_CHAIN_NAME)
|
||||
|
||||
|
||||
def test_done(task_manager):
|
||||
# run-once task
|
||||
tm = task_manager
|
||||
l = []
|
||||
|
||||
def _testDone(task, l=l):
|
||||
|
|
@ -27,28 +87,31 @@ def test_TaskManager():
|
|||
assert len(l) == 1
|
||||
tm.step()
|
||||
assert len(l) == 1
|
||||
_testDone = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_remove_by_name(task_manager):
|
||||
# remove by name
|
||||
tm = task_manager
|
||||
def _testRemoveByName(task):
|
||||
return task.done
|
||||
tm.add(_testRemoveByName, 'testRemoveByName')
|
||||
assert tm.remove('testRemoveByName') == 1
|
||||
assert tm.remove('testRemoveByName') == 0
|
||||
_testRemoveByName = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_duplicate_named_tasks(task_manager):
|
||||
# duplicate named tasks
|
||||
tm = task_manager
|
||||
def _testDupNamedTasks(task):
|
||||
return task.done
|
||||
tm.add(_testDupNamedTasks, 'testDupNamedTasks')
|
||||
tm.add(_testDupNamedTasks, 'testDupNamedTasks')
|
||||
assert tm.remove('testRemoveByName') == 0
|
||||
_testDupNamedTasks = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_continued_task(task_manager):
|
||||
# continued task
|
||||
tm = task_manager
|
||||
l = []
|
||||
|
||||
def _testCont(task, l = l):
|
||||
|
|
@ -60,10 +123,11 @@ def test_TaskManager():
|
|||
tm.step()
|
||||
assert len(l) == 2
|
||||
tm.remove('testCont')
|
||||
_testCont = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_continue_until_done(task_manager):
|
||||
# continue until done task
|
||||
tm = task_manager
|
||||
l = []
|
||||
|
||||
def _testContDone(task, l = l):
|
||||
|
|
@ -80,20 +144,22 @@ def test_TaskManager():
|
|||
tm.step()
|
||||
assert len(l) == 2
|
||||
assert not tm.hasTaskNamed('testContDone')
|
||||
_testContDone = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_has_task_named(task_manager):
|
||||
# hasTaskNamed
|
||||
tm = task_manager
|
||||
def _testHasTaskNamed(task):
|
||||
return task.done
|
||||
tm.add(_testHasTaskNamed, 'testHasTaskNamed')
|
||||
assert tm.hasTaskNamed('testHasTaskNamed')
|
||||
tm.step()
|
||||
assert not tm.hasTaskNamed('testHasTaskNamed')
|
||||
_testHasTaskNamed = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_task_sort(task_manager):
|
||||
# task sort
|
||||
tm = task_manager
|
||||
l = []
|
||||
|
||||
def _testPri1(task, l = l):
|
||||
|
|
@ -113,11 +179,11 @@ def test_TaskManager():
|
|||
assert l == [1, 2, 1, 2,]
|
||||
tm.remove('testPri1')
|
||||
tm.remove('testPri2')
|
||||
_testPri1 = None
|
||||
_testPri2 = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_extra_args(task_manager):
|
||||
# task extraArgs
|
||||
tm = task_manager
|
||||
l = []
|
||||
|
||||
def _testExtraArgs(arg1, arg2, l=l):
|
||||
|
|
@ -127,10 +193,11 @@ def test_TaskManager():
|
|||
tm.step()
|
||||
assert len(l) == 2
|
||||
assert l == [4, 5,]
|
||||
_testExtraArgs = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_append_task(task_manager):
|
||||
# task appendTask
|
||||
tm = task_manager
|
||||
l = []
|
||||
|
||||
def _testAppendTask(arg1, arg2, task, l=l):
|
||||
|
|
@ -140,10 +207,11 @@ def test_TaskManager():
|
|||
tm.step()
|
||||
assert len(l) == 2
|
||||
assert l == [4, 5,]
|
||||
_testAppendTask = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_task_upon_death(task_manager):
|
||||
# task uponDeath
|
||||
tm = task_manager
|
||||
l = []
|
||||
|
||||
def _uponDeathFunc(task, l=l):
|
||||
|
|
@ -155,11 +223,11 @@ def test_TaskManager():
|
|||
tm.step()
|
||||
assert len(l) == 1
|
||||
assert l == ['testUponDeath']
|
||||
_testUponDeath = None
|
||||
_uponDeathFunc = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_task_owner(task_manager):
|
||||
# task owner
|
||||
tm = task_manager
|
||||
class _TaskOwner:
|
||||
def _addTask(self, task):
|
||||
self.addedTaskName = task.name
|
||||
|
|
@ -175,11 +243,10 @@ def test_TaskManager():
|
|||
tm.step()
|
||||
assert getattr(to, 'addedTaskName', None) == 'testOwner'
|
||||
assert getattr(to, 'clearedTaskName', None) == 'testOwner'
|
||||
_testOwner = None
|
||||
del to
|
||||
_TaskOwner = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_do_laters(task_manager):
|
||||
tm = task_manager
|
||||
doLaterTests = [0,]
|
||||
|
||||
# doLater
|
||||
|
|
@ -205,8 +272,6 @@ def test_TaskManager():
|
|||
_testDoLater1 = None
|
||||
_testDoLater2 = None
|
||||
_monitorDoLater = None
|
||||
# don't check until all the doLaters are finished
|
||||
#tm._checkMemLeaks()
|
||||
|
||||
# doLater sort
|
||||
l = []
|
||||
|
|
@ -231,8 +296,6 @@ def test_TaskManager():
|
|||
_testDoLaterPri1 = None
|
||||
_testDoLaterPri2 = None
|
||||
_monitorDoLaterPri = None
|
||||
# don't check until all the doLaters are finished
|
||||
#tm._checkMemLeaks()
|
||||
|
||||
# doLater extraArgs
|
||||
l = []
|
||||
|
|
@ -252,8 +315,6 @@ def test_TaskManager():
|
|||
tm.add(_monitorDoLaterExtraArgs, 'monitorDoLaterExtraArgs', sort=10)
|
||||
_testDoLaterExtraArgs = None
|
||||
_monitorDoLaterExtraArgs = None
|
||||
# don't check until all the doLaters are finished
|
||||
#tm._checkMemLeaks()
|
||||
|
||||
# doLater appendTask
|
||||
l = []
|
||||
|
|
@ -275,8 +336,6 @@ def test_TaskManager():
|
|||
tm.add(_monitorDoLaterAppendTask, 'monitorDoLaterAppendTask', sort=10)
|
||||
_testDoLaterAppendTask = None
|
||||
_monitorDoLaterAppendTask = None
|
||||
# don't check until all the doLaters are finished
|
||||
#tm._checkMemLeaks()
|
||||
|
||||
# doLater uponDeath
|
||||
l = []
|
||||
|
|
@ -302,8 +361,6 @@ def test_TaskManager():
|
|||
_testUponDeathFunc = None
|
||||
_testDoLaterUponDeath = None
|
||||
_monitorDoLaterUponDeath = None
|
||||
# don't check until all the doLaters are finished
|
||||
#tm._checkMemLeaks()
|
||||
|
||||
# doLater owner
|
||||
class _DoLaterOwner:
|
||||
|
|
@ -335,15 +392,15 @@ def test_TaskManager():
|
|||
_monitorDoLaterOwner = None
|
||||
del doLaterOwner
|
||||
_DoLaterOwner = None
|
||||
# don't check until all the doLaters are finished
|
||||
#tm._checkMemLeaks()
|
||||
|
||||
# run the doLater tests
|
||||
while doLaterTests[0] > 0:
|
||||
tm.step()
|
||||
del doLaterTests
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_get_tasks(task_manager):
|
||||
tm = task_manager
|
||||
# getTasks
|
||||
def _testGetTasks(task):
|
||||
return task.cont
|
||||
|
|
@ -361,9 +418,10 @@ def test_TaskManager():
|
|||
tm.remove('testGetTasks1')
|
||||
tm.remove('testGetTasks3')
|
||||
assert len(tm.getTasks()) == 0
|
||||
_testGetTasks = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_get_do_laters(task_manager):
|
||||
tm = task_manager
|
||||
# getDoLaters
|
||||
def _testGetDoLaters():
|
||||
pass
|
||||
|
|
@ -379,9 +437,18 @@ def test_TaskManager():
|
|||
tm.remove('testDoLater1')
|
||||
tm.remove('testDoLater3')
|
||||
assert len(tm.getDoLaters()) == 0
|
||||
_testGetDoLaters = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_get_all_tasks(task_manager):
|
||||
active_task = task_manager.add(DUMMY_FUNCTION, delay=None)
|
||||
sleeping_task = task_manager.add(DUMMY_FUNCTION, delay=1)
|
||||
assert task_manager.getTasks() == [active_task]
|
||||
assert task_manager.getDoLaters() == [sleeping_task]
|
||||
assert task_manager.getAllTasks() in ([active_task, sleeping_task], [sleeping_task, active_task])
|
||||
|
||||
|
||||
def test_duplicate_named_do_laters(task_manager):
|
||||
tm = task_manager
|
||||
# duplicate named doLaters removed via taskMgr.remove
|
||||
def _testDupNameDoLaters():
|
||||
pass
|
||||
|
|
@ -391,9 +458,10 @@ def test_TaskManager():
|
|||
assert len(tm.getDoLaters()) == 2
|
||||
tm.remove('testDupNameDoLater')
|
||||
assert len(tm.getDoLaters()) == 0
|
||||
_testDupNameDoLaters = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_duplicate_named_do_laters_remove(task_manager):
|
||||
tm = task_manager
|
||||
# duplicate named doLaters removed via remove()
|
||||
def _testDupNameDoLatersRemove():
|
||||
pass
|
||||
|
|
@ -405,10 +473,10 @@ def test_TaskManager():
|
|||
assert len(tm.getDoLaters()) == 1
|
||||
dl1.remove()
|
||||
assert len(tm.getDoLaters()) == 0
|
||||
_testDupNameDoLatersRemove = None
|
||||
# nameDict etc. isn't cleared out right away with task.remove()
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_get_tasks_named(task_manager):
|
||||
tm = task_manager
|
||||
# getTasksNamed
|
||||
def _testGetTasksNamed(task):
|
||||
return task.cont
|
||||
|
|
@ -421,9 +489,20 @@ def test_TaskManager():
|
|||
assert len(tm.getTasksNamed('testGetTasksNamed')) == 3
|
||||
tm.remove('testGetTasksNamed')
|
||||
assert len(tm.getTasksNamed('testGetTasksNamed')) == 0
|
||||
_testGetTasksNamed = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_get_tasks_matching(task_manager):
|
||||
task_manager.add(DUMMY_FUNCTION, 'task_1')
|
||||
task_manager.add(DUMMY_FUNCTION, 'task_2')
|
||||
task_manager.add(DUMMY_FUNCTION, 'another_task')
|
||||
|
||||
assert len(task_manager.getTasksMatching('task_?')) == 2
|
||||
assert len(task_manager.getTasksMatching('*_task')) == 1
|
||||
assert len(task_manager.getTasksMatching('*task*')) == 3
|
||||
|
||||
|
||||
def test_remove_tasks_matching(task_manager):
|
||||
tm = task_manager
|
||||
# removeTasksMatching
|
||||
def _testRemoveTasksMatching(task):
|
||||
return task.cont
|
||||
|
|
@ -445,9 +524,10 @@ def test_TaskManager():
|
|||
tm.removeTasksMatching('testRemoveTasksMatching?a')
|
||||
assert len(tm.getTasksNamed('testRemoveTasksMatching1a')) == 0
|
||||
assert len(tm.getTasksNamed('testRemoveTasksMatching2a')) == 0
|
||||
_testRemoveTasksMatching = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_task_obj(task_manager):
|
||||
tm = task_manager
|
||||
# create Task object and add to mgr
|
||||
l = []
|
||||
|
||||
|
|
@ -463,9 +543,10 @@ def test_TaskManager():
|
|||
tm.remove('testTaskObj')
|
||||
tm.step()
|
||||
assert len(l) == 2
|
||||
_testTaskObj = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_task_remove(task_manager):
|
||||
tm = task_manager
|
||||
# remove Task via task.remove()
|
||||
l = []
|
||||
|
||||
|
|
@ -482,9 +563,10 @@ def test_TaskManager():
|
|||
tm.step()
|
||||
assert len(l) == 2
|
||||
del t
|
||||
_testTaskObjRemove = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
|
||||
def test_task_get_sort(task_manager):
|
||||
tm = task_manager
|
||||
# set/get Task sort
|
||||
l = []
|
||||
def _testTaskObjSort(arg, task, l=l):
|
||||
|
|
@ -508,11 +590,3 @@ def test_TaskManager():
|
|||
t2.remove()
|
||||
tm.step()
|
||||
assert len(l) == 4
|
||||
del t1
|
||||
del t2
|
||||
_testTaskObjSort = None
|
||||
tm._checkMemLeaks()
|
||||
|
||||
del l
|
||||
tm.destroy()
|
||||
del tm
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
# missing imports. It is useful for a quick and dirty test to make sure
|
||||
# that there are no obvious build issues.
|
||||
import pytest
|
||||
import sys
|
||||
|
||||
# This will print out imports on the command line.
|
||||
#import direct.showbase.VerboseImport
|
||||
|
|
@ -9,7 +10,7 @@ import pytest
|
|||
|
||||
|
||||
def test_imports_panda3d():
|
||||
import importlib, os, sys
|
||||
import importlib, os
|
||||
import panda3d
|
||||
|
||||
# Look for panda3d.* modules in builtins - pfreeze might put them there.
|
||||
|
|
@ -165,7 +166,8 @@ def test_imports_direct():
|
|||
import direct.showbase.TaskThreaded
|
||||
import direct.showbase.ThreeUpShow
|
||||
import direct.showbase.Transitions
|
||||
import direct.showbase.VFSImporter
|
||||
if sys.version_info < (3, 12):
|
||||
import direct.showbase.VFSImporter
|
||||
import direct.showbase.WxGlobal
|
||||
import direct.showutil.BuildGeometry
|
||||
import direct.showutil.Effects
|
||||
|
|
|
|||
Loading…
Reference in New Issue