From b9c1765ab4e840cf4ccfde7e9512effb800e77c4 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 11 Feb 2015 21:12:54 +0100 Subject: [PATCH 01/32] Fix eggcacher, dramatically improve Windows installer --- direct/src/directbase/ppython.cxx | 8 +- direct/src/directscripts/eggcacher.py | 12 +- makepanda/installer.nsi | 1276 +++++++++++++++++ makepanda/makepanda.py | 26 +- .../panda-install.bmp | Bin panda/src/pgraph/loader.cxx | 8 +- panda/src/putil/bamCache.cxx | 30 +- panda/src/putil/bamCache.h | 10 +- 8 files changed, 1326 insertions(+), 44 deletions(-) create mode 100755 makepanda/installer.nsi rename {direct/src/directscripts => makepanda}/panda-install.bmp (100%) diff --git a/direct/src/directbase/ppython.cxx b/direct/src/directbase/ppython.cxx index df16243c61..4d673d96b6 100755 --- a/direct/src/directbase/ppython.cxx +++ b/direct/src/directbase/ppython.cxx @@ -7,6 +7,8 @@ // /////////////////////////////////////////////////////////////////////// +#include "dtoolbase.h" + #include #if PY_MAJOR_VERSION >= 3 #include @@ -71,7 +73,7 @@ int main(int argc, char *argv[]) { char *path = getenv("PATH"); char *result = strtok(path, ";"); while (result != NULL) { - struct stat st; + struct stat st; char *ppython = (char*) malloc(strlen(result) + 13); strcpy(ppython, result); strcat(ppython, "\\ppython.exe"); @@ -79,13 +81,13 @@ int main(int argc, char *argv[]) { Py_SetPythonHome(result); free(ppython); break; - } + } result = strtok(NULL, ";"); free(ppython); } #endif #endif - + Py_Initialize(); if (Py_VerboseFlag) { diff --git a/direct/src/directscripts/eggcacher.py b/direct/src/directscripts/eggcacher.py index c742df2ab6..ea2f653876 100644 --- a/direct/src/directscripts/eggcacher.py +++ b/direct/src/directscripts/eggcacher.py @@ -9,15 +9,15 @@ ############################################################################## import os,sys,gc -from pandac.PandaModules import * +from panda3d.core import * class EggCacher: def __init__(self, args): maindir = Filename.fromOsSpecific(os.getcwd()).getFullpath() ExecutionEnvironment.setEnvironmentVariable("MAIN_DIR", maindir) self.bamcache = BamCache.getGlobalPtr() - self.pandaloader = PandaLoader() - self.loaderopts = LoaderOptions() + self.pandaloader = Loader() + self.loaderopts = LoaderOptions(LoaderOptions.LF_no_ram_cache) if (self.bamcache.getActive() == 0): print "The model cache is not currently active." print "You must set a model-cache-dir in your config file." @@ -69,12 +69,12 @@ class EggCacher: def processFiles(self, files): total = 0 - for (path,size) in files: + for (path, size) in files: total += size progress = 0 for (path,size) in files: fn = Filename.fromOsSpecific(path) - cached = self.bamcache.lookup(fn,"bam") + cached = self.bamcache.lookup(fn, "bam") percent = (progress * 100) / total report = path if (self.concise): report = os.path.basename(report) @@ -87,6 +87,4 @@ class EggCacher: TexturePool.releaseAllTextures() progress += size - cacher = EggCacher(sys.argv[1:]) - diff --git a/makepanda/installer.nsi b/makepanda/installer.nsi new file mode 100755 index 0000000000..e0b838c48f --- /dev/null +++ b/makepanda/installer.nsi @@ -0,0 +1,1276 @@ +; Panda3D installation script for the Nullsoft Installation System (NSIS). +; Jon Parise +; with Ben Johnson +; with Jason Pratt +; mangled by Josh Yelon +; Heavily restructured by rdb + +; Caller needs to define these variables: +; +; COMPRESSOR - either zlib or lzma +; TITLE - title (eg. "Panda3D SDK 1.9.0") +; INSTALLDIR - default install location (eg. "C:\Panda3D-1.9.0-x64") +; OUTFILE - where to put the output file (eg. "..\nsis-output.exe") +; +; BUILT - location of panda install tree. +; SOURCE - location of the panda source-tree if available, OR location of panda install tree. +; PYVER - version of Python that Panda was built with (ie, "2.7") +; PYEXTRAS - directory containing python extras, if any. +; REGVIEW - either 32 or 64, depending on the build architecture. +; + +Name "${TITLE}" +InstallDir "${INSTALLDIR}" +OutFile "${OUTFILE}" + +RequestExecutionLevel user + +SetCompress auto +SetCompressor ${COMPRESSOR} + +!include "MUI2.nsh" +!include "Sections.nsh" +!include "WinMessages.nsh" +!include "WordFunc.nsh" + +!define MUI_WELCOMEFINISHPAGE_BITMAP "panda-install.bmp" +!define MUI_UNWELCOMEFINISHPAGE_BITMAP "panda-install.bmp" + +!define MUI_ABORTWARNING +!define MUI_FINISHPAGE_NOREBOOTSUPPORT +!define MUI_FINISHPAGE_RUN +!define MUI_FINISHPAGE_RUN_FUNCTION runFunction +!define MUI_FINISHPAGE_RUN_TEXT "Visit the Panda3D Manual" + +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_LICENSE "../doc/LICENSE" +!insertmacro MUI_PAGE_DIRECTORY + +!define MUI_PAGE_CUSTOMFUNCTION_LEAVE ConfirmPythonSelection +!insertmacro MUI_PAGE_COMPONENTS + +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_PAGE_FINISH + +!insertmacro MUI_UNPAGE_WELCOME +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_UNPAGE_FINISH + +!insertmacro MUI_LANGUAGE "English" + +ShowInstDetails hide +ShowUninstDetails hide + +LicenseData "${LICENSE}" + +InstType "Full (Recommended)" +InstType "Minimal" + +LangString DESC_SecCore ${LANG_ENGLISH} "The Panda3D core libraries, configuration files and models/textures that are needed to use Panda3D." +LangString DESC_SecOpenGL ${LANG_ENGLISH} "The OpenGL graphics back-end is the most well-supported renderer." +LangString DESC_SecDirect3D9 ${LANG_ENGLISH} "The optional Direct3D 9 renderer." +LangString DESC_SecOpenAL ${LANG_ENGLISH} "Support for playing audio via the OpenAL library. You need either OpenAL or FMOD to be able to play audio." +LangString DESC_SecFMOD ${LANG_ENGLISH} "Support for decoding and playing audio via the FMOD Ex library. You need either OpenAL or FMOD to be able to play audio." +LangString DESC_SecFFMpeg ${LANG_ENGLISH} "Support for decoding video and audio via the FFMpeg library. Without this option, Panda3D will only be able to play .wav and .ogg audio files." +LangString DESC_SecBullet ${LANG_ENGLISH} "Support for the Bullet physics engine." +LangString DESC_SecODE ${LANG_ENGLISH} "Support for the Open Dynamics Engine to implement physics." +LangString DESC_SecPhysX ${LANG_ENGLISH} "Support for NVIDIA PhysX to implement physics." +LangString DESC_SecRocket ${LANG_ENGLISH} "Support for the libRocket GUI library. This is an optional library that offers an HTML/CSS-like approach to creating user interfaces." +LangString DESC_SecTools ${LANG_ENGLISH} "Useful tools and model converters to help with Panda3D development. Recommended." +LangString DESC_SecPyBindings ${LANG_ENGLISH} "Contains the Python modules that allow use of Panda3D using Python. These will only work with a ${REGVIEW}-bit version of Python ${PYVER}." +LangString DESC_SecPython ${LANG_ENGLISH} "Contains a ${REGVIEW}-bit copy of Python ${PYVER} preconfigured to make use of Panda3D." +LangString DESC_SecHeadersLibs ${LANG_ENGLISH} "Headers and libraries needed for C++ development with Panda3D." +LangString DESC_SecSamples ${LANG_ENGLISH} "The sample programs demonstrate how to make Python applications with Panda3D." +LangString DESC_SecMaxPlugins ${LANG_ENGLISH} "Plug-ins for Autodesk 3ds Max (${REGVIEW}-bit) that can be used to export models to Panda3D." +LangString DESC_SecMayaPlugins ${LANG_ENGLISH} "Plug-ins and scripts for Autodesk Maya (${REGVIEW}-bit) that can be used to export models to Panda3D." + +var READABLE +var MANPAGE + +; See http://nsis.sourceforge.net/Check_if_a_file_exists_at_compile_time for documentation +!macro !defineifexist _VAR_NAME _FILE_NAME + !tempfile _TEMPFILE + !ifdef NSIS_WIN32_MAKENSIS + ; Windows - cmd.exe + !system 'if exist "${_FILE_NAME}" echo !define ${_VAR_NAME} > "${_TEMPFILE}"' + !else + ; Posix - sh + !system 'if [ -e "${_FILE_NAME}" ]; then echo "!define ${_VAR_NAME}" > "${_TEMPFILE}"; fi' + !endif + !include '${_TEMPFILE}' + !delfile '${_TEMPFILE}' + !undef _TEMPFILE +!macroend + +!insertmacro !defineifexist HAVE_GL "${BUILT}\bin\libpandagl.dll" +!insertmacro !defineifexist HAVE_DX9 "${BUILT}\bin\libpandadx9.dll" +!insertmacro !defineifexist HAVE_OPENAL "${BUILT}\bin\libp3openal_audio.dll" +!insertmacro !defineifexist HAVE_FMOD "${BUILT}\bin\libp3fmod_audio.dll" +!insertmacro !defineifexist HAVE_FFMPEG "${BUILT}\bin\libp3ffmpeg.dll" +!insertmacro !defineifexist HAVE_BULLET "${BUILT}\bin\libpandabullet.dll" +!insertmacro !defineifexist HAVE_ODE "${BUILT}\bin\libpandaode.dll" +!insertmacro !defineifexist HAVE_PHYSX "${BUILT}\bin\libpandaphysx.dll" +!insertmacro !defineifexist HAVE_ROCKET "${BUILT}\bin\libp3rocket.dll" +!insertmacro !defineifexist HAVE_PYTHON "${BUILT}\python" +!insertmacro !defineifexist HAVE_SAMPLES "${SOURCE}\samples" +!insertmacro !defineifexist HAVE_MAX_PLUGINS "${BUILT}\plugins\*.dlo" +!insertmacro !defineifexist HAVE_MAYA_PLUGINS "${BUILT}\plugins\*.mll" + +Function runFunction + ExecShell "open" "$SMPROGRAMS\${TITLE}\Panda3D Manual.lnk" +FunctionEnd + +SectionGroup "Panda3D Libraries" + Section "Core Libraries" SecCore + SectionIn 1 2 RO + + SetShellVarContext current + SetOverwrite try + + SetDetailsPrint both + DetailPrint "Installing Panda3D libraries..." + SetDetailsPrint listonly + + SetOutPath "$INSTDIR" + File "${BUILT}\LICENSE" + File /r /x CVS "${BUILT}\ReleaseNotes" + SetOutPath $INSTDIR\bin + File /r /x libpandagl.dll /x libpandadx9.dll /x cgD3D*.dll /x python*.dll /x libpandaode.dll /x libp3fmod_audio.dll /x fmodex*.dll /x libp3ffmpeg.dll /x av*.dll /x postproc*.dll /x swscale*.dll /x swresample*.dll /x libp3rocket.dll /x boost_python*.dll /x Rocket*.dll /x _rocket*.pyd /x libpandabullet.dll /x OpenAL32.dll /x *_oal.dll /x libp3openal_audio.dll "${BUILT}\bin\*.dll" + File /nonfatal /r "${BUILT}\bin\Microsoft.*.manifest" + SetOutPath $INSTDIR\etc + File /r "${BUILT}\etc\*" + + SetDetailsPrint both + DetailPrint "Installing models..." + SetDetailsPrint listonly + + SetOutPath $INSTDIR\models + File /r /x CVS "${BUILT}\models\*" + + RMDir /r "$SMPROGRAMS\${TITLE}" + CreateDirectory "$SMPROGRAMS\${TITLE}" + SectionEnd + + !ifdef HAVE_GL + Section "OpenGL" SecOpenGL + SectionIn 1 2 RO + + SetOutPath "$INSTDIR\bin" + File "${BUILT}\bin\libpandagl.dll" + SectionEnd + !endif + + !ifdef HAVE_DX9 + Section "Direct3D 9" SecDirect3D9 + SectionIn 1 + + SetOutPath "$INSTDIR\bin" + File "${BUILT}\bin\libpandadx9.dll" + File /nonfatal /r "${BUILT}\bin\cgD3D9.dll" + SectionEnd + !endif + + !ifdef HAVE_OPENAL + Section "OpenAL Audio" SecOpenAL + SectionIn 1 2 + + SetOutPath "$INSTDIR\bin" + File "${BUILT}\bin\libp3openal_audio.dll" + File /nonfatal /r "${BUILT}\bin\OpenAL32.dll" + File /nonfatal /r "${BUILT}\bin\*_oal.dll" + SectionEnd + !endif + + !ifdef HAVE_FMOD + Section "FMOD Audio" SecFMOD + SectionIn 1 + + SetOutPath "$INSTDIR\bin" + File "${BUILT}\bin\libp3fmod_audio.dll" + File /r "${BUILT}\bin\fmodex*.dll" + SectionEnd + !endif + + !ifdef HAVE_FFMPEG + Section "FFMpeg" SecFFMpeg + SectionIn 1 + + SetOutPath "$INSTDIR\bin" + File "${BUILT}\bin\libp3ffmpeg.dll" + File /nonfatal /r "${BUILT}\bin\av*.dll" + File /nonfatal /r "${BUILT}\bin\swscale*.dll" + File /nonfatal /r "${BUILT}\bin\swresample*.dll" + File /nonfatal /r "${BUILT}\bin\postproc*.dll" + SectionEnd + !endif + + !ifdef HAVE_BULLET + Section "Bullet Physics" SecBullet + SectionIn 1 + + SetOutPath "$INSTDIR\bin" + File "${BUILT}\bin\libpandabullet.dll" + SectionEnd + !endif + + !ifdef HAVE_ODE + Section "ODE Physics" SecODE + SectionIn 1 + + SetOutPath "$INSTDIR\bin" + File "${BUILT}\bin\libpandaode.dll" + SectionEnd + !endif + + !ifdef HAVE_ROCKET + Section "libRocket GUI" SecRocket + SectionIn 1 + + SetOutPath "$INSTDIR\bin" + File "${BUILT}\bin\libp3rocket.dll" + File /nonfatal /r "${BUILT}\bin\Rocket*.dll" + File /nonfatal /r "${BUILT}\bin\_rocket*.pyd" + File /nonfatal /r "${BUILT}\bin\boost_python*.dll" + SectionEnd + !endif +SectionGroupEnd + +Section "Tools and utilities" SecTools + SectionIn 1 2 + + SetDetailsPrint both + DetailPrint "Installing utilities..." + SetDetailsPrint listonly + + SetOutPath "$INSTDIR\bin" + File /r "${BUILT}\bin\*.exe" + File /nonfatal /r "${BUILT}\bin\*.p3d" + SetOutPath "$INSTDIR\NSIS" + File /r /x CVS "${NSISDIR}\*" +SectionEnd + +SectionGroup "Python support" + Section "Python bindings" SecPyBindings + SectionIn 1 2 + + SetDetailsPrint both + DetailPrint "Installing Panda3D Python modules..." + SetDetailsPrint listonly + + SetOutPath "$INSTDIR\bin" + File /nonfatal /r "${BUILT}\bin\*.pyd" + + SetOutPath $INSTDIR\direct\directscripts + File /r /x CVS /x Opt?-Win32 "${BUILT}\direct\directscripts\*" + SetOutPath $INSTDIR\direct\filter + File /r /x CVS /x Opt?-Win32 "${BUILT}\direct\filter\*.sha" + SetOutPath $INSTDIR\direct + File /r /x CVS /x Opt?-Win32 "${BUILT}\direct\*.py" + + Delete "$INSTDIR\panda3d.py" + Delete "$INSTDIR\panda3d.pyc" + Delete "$INSTDIR\panda3d.pyo" + SetOutPath $INSTDIR\pandac + File /r "${BUILT}\pandac\*.py" + SetOutPath $INSTDIR\panda3d + File /r "${BUILT}\panda3d\*.py" + + File /r /x bullet.pyd /x ode.pyd /x physx.pyd /x rocket.pyd "${BUILT}\panda3d\*.pyd" + + !ifdef HAVE_BULLET + SectionGetFlags ${SecBullet} $R0 + IntOp $R0 $R0 & ${SF_SELECTED} + StrCmp $R0 ${SF_SELECTED} 0 SkipBulletPyd + File /nonfatal /r "${BUILT}\panda3d\bullet.pyd" + SkipBulletPyd: + !endif + + !ifdef HAVE_ODE + SectionGetFlags ${SecODE} $R0 + IntOp $R0 $R0 & ${SF_SELECTED} + StrCmp $R0 ${SF_SELECTED} 0 SkipODEPyd + File /nonfatal /r "${BUILT}\panda3d\ode.pyd" + SkipODEPyd: + !endif + + !ifdef HAVE_PHYSX + SectionGetFlags ${SecPhysX} $R0 + IntOp $R0 $R0 & ${SF_SELECTED} + StrCmp $R0 ${SF_SELECTED} 0 SkipPhysXPyd + File /nonfatal /r "${BUILT}\panda3d\physx.pyd" + SkipPhysXPyd: + !endif + + !ifdef HAVE_ROCKET + SectionGetFlags ${SecRocket} $R0 + IntOp $R0 $R0 & ${SF_SELECTED} + StrCmp $R0 ${SF_SELECTED} 0 SkipRocketPyd + File /nonfatal /r "${BUILT}\panda3d\rocket.pyd" + SkipRocketPyd: + !endif + + SetOutPath $INSTDIR\pandac\input + File /r "${BUILT}\pandac\input\*" + SetOutPath $INSTDIR\Pmw + File /r /x CVS "${BUILT}\Pmw\*" + + ; Check for a user installation of Python. + ReadRegStr $0 HKCU "Software\Python\PythonCore\${PYVER}\InstallPath" "" + StrCmp $0 "$INSTDIR\python" CheckSystemWidePython 0 + StrCmp $0 "" CheckSystemWidePython 0 + IfFileExists "$0\ppython.exe" CheckSystemWidePython 0 + IfFileExists "$0\python.exe" AskExternalPth 0 + + ; Check for a system-wide Python installation. + CheckSystemWidePython: + ReadRegStr $0 HKLM "Software\Python\PythonCore\${PYVER}\InstallPath" "" + StrCmp $0 "$INSTDIR\python" SkipExternalPth 0 + StrCmp $0 "" SkipExternalPth 0 + IfFileExists "$0\ppython.exe" SkipExternalPth 0 + IfFileExists "$0\python.exe" AskExternalPth SkipExternalPth + + AskExternalPth: + MessageBox MB_YESNO|MB_ICONQUESTION \ + "Your system already has a ${REGVIEW}-bit copy of Python ${PYVER} installed in:$\r$\n$0$\r$\nWould you like to configure it to be able to use the Panda3D libraries?$\r$\nIf you choose no, you will only be able to use Panda3D's own copy of Python." \ + IDNO SkipExternalPth + + FileOpen $1 "$0\Lib\site-packages\panda.pth" w + FileWrite $1 "$INSTDIR$\r$\n" + FileWrite $1 "$INSTDIR\bin$\r$\n" + FileClose $1 + SkipExternalPth: + SectionEnd + + !ifdef HAVE_PYTHON + Section "Python ${PYVER}" SecPython + SectionIn 1 2 + + !ifdef REGVIEW + SetRegView ${REGVIEW} + !endif + + SetDetailsPrint both + DetailPrint "Installing Python ${PYVER} (${REGVIEW}-bit)..." + SetDetailsPrint listonly + + SetOutPath "$INSTDIR\bin" + File /nonfatal "${BUILT}\bin\python*.dll" + + SetOutPath "$INSTDIR\python" + File /r "${BUILT}\python\*" + + !ifdef PYEXTRAS + SetOutPath "$INSTDIR\python\lib" + File /nonfatal /r "${PYEXTRAS}\*" + !endif + + SetDetailsPrint both + DetailPrint "Adding registry keys for Python..." + SetDetailsPrint listonly + + ; Check if a copy of Python is installed for this user. + ReadRegStr $0 HKCU "Software\Python\PythonCore\${PYVER}\InstallPath" "" + StrCmp "$0" "$INSTDIR\python" RegPath 0 + StrCmp "$0" "" SkipFileCheck 0 + IfFileExists "$0\python.exe" AskRegPath 0 + SkipFileCheck: + + ; Check if a system-wide copy of Python is installed. + ReadRegStr $0 HKLM "Software\Python\PythonCore\${PYVER}\InstallPath" "" + StrCmp "$0" "$INSTDIR\python" RegPath 0 + StrCmp "$0" "" RegPath 0 + IfFileExists "$0\python.exe" AskRegPath RegPath + + AskRegPath: + MessageBox MB_YESNO|MB_ICONQUESTION \ + "Your system already has a ${REGVIEW}-bit copy of Python ${PYVER} installed in:$\r$\n$0$\r$\n$\r$\nPanda3D installs its own copy of Python ${PYVER}, which will install alongside your existing copy. Would you like to make Panda's copy the default Python for your user account?" \ + IDNO SkipRegPath + + RegPath: + WriteRegStr HKCU "Software\Python\PythonCore\${PYVER}\InstallPath" "" "$INSTDIR\python" + SkipRegPath: + + SectionEnd + !endif +SectionGroupEnd + +Function ConfirmPythonSelection + ; Check the current state of the "Python" section selection. + SectionGetFlags ${SecPython} $R0 + IntOp $R1 $R0 & ${SF_SELECTED} + + ; Is the "Python" selection deselected? + StrCmp $R1 ${SF_SELECTED} SkipCheck 0 + + ; Maybe the user just doesn't want Python support at all? + SectionGetFlags ${SecPyBindings} $R1 + IntOp $R1 $R1 & ${SF_SELECTED} + StrCmp $R1 ${SF_SELECTED} 0 SkipCheck + + ; Check for a user installation of Python. + ReadRegStr $0 HKCU "Software\Python\PythonCore\${PYVER}\InstallPath" "" + StrCmp $0 "$INSTDIR\python" CheckSystemWidePython 0 + StrCmp $0 "" CheckSystemWidePython 0 + IfFileExists "$0\ppython.exe" CheckSystemWidePython 0 + IfFileExists "$0\python.exe" SkipCheck CheckSystemWidePython + + ; Check for a system-wide Python installation. + CheckSystemWidePython: + ReadRegStr $0 HKLM "Software\Python\PythonCore\${PYVER}\InstallPath" "" + StrCmp $0 "$INSTDIR\python" AskConfirmation 0 + StrCmp $0 "" AskConfirmation 0 + IfFileExists "$0\ppython.exe" AskConfirmation 0 + IfFileExists "$0\python.exe" SkipCheck AskConfirmation + + ; No compatible Python version found (that wasn't shipped as part + ; of a different Panda3D build.) Ask the user if he's sure about this. + AskConfirmation: + MessageBox MB_YESNO|MB_ICONQUESTION \ + "You do not appear to have a ${REGVIEW}-bit version of Python ${PYVER} installed that is compatible with Panda3D. Are you sure you don't want Panda to install a compatible copy of Python?$\r$\n$\r$\nIf you choose Yes, you will not be able to do Python development with Panda3D until you install a ${REGVIEW}-bit version of Python ${PYVER} and manually configure it to be able to use Panda3D." \ + IDYES SkipCheck + + ; User clicked no, so re-enable the select box and abort. + IntOp $R0 $R0 | ${SF_SELECTED} + SectionSetFlags ${SecPython} $R0 + Abort + + SkipCheck: +FunctionEnd + +Section "C++ support" SecHeadersLibs + SectionIn 1 + + SetDetailsPrint both + DetailPrint "Installing header files..." + SetDetailsPrint listonly + + SetOutPath $INSTDIR\include + File /r /x *.exp "${BUILT}\include\*" + + SetDetailsPrint both + DetailPrint "Installing library archives..." + SetDetailsPrint listonly + + SetOutPath $INSTDIR\lib + File /r /x *.exp "${BUILT}\lib\*" +SectionEnd + +!ifdef HAVE_SAMPLES +Section "Sample programs" SecSamples + SectionIn 1 + + ; Necessary for proper start menu shortcut installation + SetShellVarContext current + + SetDetailsPrint both + DetailPrint "Installing sample programs..." + SetDetailsPrint listonly + + SetOutPath $INSTDIR\samples + File /nonfatal /r /x CVS "${SOURCE}\samples\*" + + SetDetailsPrint both + DetailPrint "Creating shortcuts..." + SetDetailsPrint listonly + + SetOutPath $INSTDIR + WriteINIStr $INSTDIR\Website.url "InternetShortcut" "URL" "https://www.panda3d.org/" + WriteINIStr $INSTDIR\Manual.url "InternetShortcut" "URL" "https://www.panda3d.org/manual/index.php" + WriteINIStr $INSTDIR\Samples.url "InternetShortcut" "URL" "https://www.panda3d.org/manual/index.php/Sample_Programs_in_the_Distribution" + SetOutPath $INSTDIR + CreateShortCut "$SMPROGRAMS\${TITLE}\Panda3D Manual.lnk" "$INSTDIR\Manual.url" "" "$INSTDIR\bin\eggcacher.exe" 0 "" "" "Panda3D Manual" + CreateShortCut "$SMPROGRAMS\${TITLE}\Panda3D Website.lnk" "$INSTDIR\Website.url" "" "$INSTDIR\bin\eggcacher.exe" 0 "" "" "Panda3D Website" + CreateShortCut "$SMPROGRAMS\${TITLE}\Sample Program Manual.lnk" "$INSTDIR\Samples.url" "" "$INSTDIR\bin\eggcacher.exe" 0 "" "" "Sample Program Manual" + + FindFirst $0 $1 $INSTDIR\samples\* + loop: + StrCmp $1 "" done + StrCmp $1 "." next + StrCmp $1 ".." next + Push $1 + Push "-" + Push " " + Call StrRep + Call Capitalize + Pop $R0 + StrCpy $READABLE $R0 + Push $1 + Push "-" + Push "_" + Call StrRep + Pop $R0 + StrCpy $MANPAGE $R0 + DetailPrint "Creating shortcuts for sample program $READABLE" + CreateDirectory "$SMPROGRAMS\${TITLE}\Sample Programs\$READABLE" + SetOutPath $INSTDIR\samples\$1 + WriteINIStr $INSTDIR\samples\$1\ManualPage.url "InternetShortcut" "URL" "http://panda3d.org/wiki/index.php/Sample_Programs:_$MANPAGE" + CreateShortCut "$SMPROGRAMS\${TITLE}\Sample Programs\$READABLE\Manual Page.lnk" "$INSTDIR\samples\$1\ManualPage.url" "" "$INSTDIR\bin\eggcacher.exe" 0 "" "" "Manual Entry on this Sample Program" + CreateShortCut "$SMPROGRAMS\${TITLE}\Sample Programs\$READABLE\View Source Code.lnk" "$INSTDIR\samples\$1" + FindFirst $2 $3 $INSTDIR\samples\$1\*.py + iloop: + StrCmp $3 "" idone + CreateShortCut "$SMPROGRAMS\${TITLE}\Sample Programs\$READABLE\Run $3.lnk" "$INSTDIR\python\python.exe" "-E $3" "$INSTDIR\bin\eggcacher.exe" 0 SW_SHOWMINIMIZED "" "Run $3" + CreateShortCut "$INSTDIR\samples\$1\Run $3.lnk" "$INSTDIR\python\python.exe" "-E $3" "$INSTDIR\bin\eggcacher.exe" 0 SW_SHOWMINIMIZED "" "Run $3" + FindNext $2 $3 + goto iloop + idone: + next: + FindNext $0 $1 + Goto loop + done: +SectionEnd +!endif + +!ifdef HAVE_MAX_PLUGINS +Section "3ds Max plug-ins" SecMaxPlugins + SectionIn 1 3 + + SetDetailsPrint both + DetailPrint "Installing Autodesk 3ds Max plug-ins..." + SetDetailsPrint listonly + + SetOutPath $INSTDIR\plugins + File /nonfatal /r "${BUILT}\plugins\*.dle" + File /nonfatal /r "${BUILT}\plugins\*.dlo" + File "${SOURCE}\doc\INSTALLING-PLUGINS.TXT" +SectionEnd +!endif + +!ifdef HAVE_MAYA_PLUGINS +Section "Maya plug-ins" SecMayaPlugins + SectionIn 1 3 + + SetDetailsPrint both + DetailPrint "Installing Autodesk Maya plug-ins..." + SetDetailsPrint listonly + + SetOutPath $INSTDIR\plugins + File /nonfatal /r "${BUILT}\plugins\*.mll" + File /nonfatal /r "${BUILT}\plugins\*.mel" + File /nonfatal /r "${BUILT}\plugins\*.ms" + File "${SOURCE}\doc\INSTALLING-PLUGINS.TXT" +SectionEnd +!endif + +Section -post + !ifdef REGVIEW + SetRegView ${REGVIEW} + !endif + + ; Run eggcacher. We can't do this in SecCore because we haven't + ; installed eggcacher at that point yet. + SetDetailsPrint both + DetailPrint "Preloading .egg files into the model cache..." + SetDetailsPrint listonly + + ; We need to set the $PATH for eggcacher. + SetOutPath $INSTDIR + ReadEnvStr $R0 "PATH" + StrCpy $R0 "$INSTDIR\python;$INSTDIR\bin;$R0" + System::Call 'Kernel32::SetEnvironmentVariableA(t, t) i("PATH", R0).r2' + + nsExec::ExecToLog '"$INSTDIR\bin\eggcacher.exe" --concise models samples' + + SetDetailsPrint both + DetailPrint "Writing the uninstaller ..." + SetDetailsPrint listonly + + Delete "$INSTDIR\uninst.exe" + WriteUninstaller "$INSTDIR\uninst.exe" + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${TITLE}" "DisplayName" "${TITLE}" + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${TITLE}" "UninstallString" '"$INSTDIR\uninst.exe"' + SetOutPath $INSTDIR + CreateShortcut "$SMPROGRAMS\${TITLE}\Uninstall ${TITLE}.lnk" "$INSTDIR\uninst.exe" "" + + SetDetailsPrint both + DetailPrint "Adding directories to system PATH..." + SetDetailsPrint listonly + + # Add the "bin" directory to the PATH. + Push "$INSTDIR\python" + Call RemoveFromPath + Push "$INSTDIR\python\Scripts" + Call RemoveFromPath + Push "$INSTDIR\bin" + Call RemoveFromPath + Push "$INSTDIR\python" + Call AddToPath + Push "$INSTDIR\python\Scripts" + Call AddToPath + Push "$INSTDIR\bin" + Call AddToPath + + # This is needed for the environment variable changes to take effect. + DetailPrint "Broadcasting WM_WININICHANGE message..." + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=500 + +SectionEnd + +Section Uninstall + SetDetailsPrint listonly + + SetShellVarContext current + !ifdef REGVIEW + SetRegView ${REGVIEW} + !endif + + SetDetailsPrint both + DetailPrint "Removing registry entries..." + SetDetailsPrint listonly + + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${TITLE}" + DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${TITLE}" + + ReadRegStr $0 HKLM "Software\Python\PythonCore\${PYVER}\InstallPath" "" + StrCmp $0 "$INSTDIR\python" 0 SkipUnRegHKLM + DeleteRegKey HKLM "Software\Python\PythonCore\${PYVER}" + SkipUnRegHKLM: + + ReadRegStr $0 HKCU "Software\Python\PythonCore\${PYVER}\InstallPath" "" + StrCmp $0 "$INSTDIR\python" 0 SkipUnRegHKCU + DeleteRegKey HKCU "Software\Python\PythonCore\${PYVER}" + SkipUnRegHKCU: + + SetDetailsPrint both + DetailPrint "Deleting files..." + SetDetailsPrint listonly + + Delete "$INSTDIR\uninst.exe" + RMDir /r "$INSTDIR" + + SetDetailsPrint both + DetailPrint "Removing Start Menu entries..." + SetDetailsPrint listonly + + SetShellVarContext current + RMDir /r "$SMPROGRAMS\${TITLE}" + SetShellVarContext all + RMDir /r "$SMPROGRAMS\${TITLE}" + + SetDetailsPrint both + DetailPrint "Removing entries from PATH..." + SetDetailsPrint listonly + + Push "$INSTDIR\python" + Call un.RemoveFromPath + Push "$INSTDIR\python\Scripts" + Call un.RemoveFromPath + Push "$INSTDIR\bin" + Call un.RemoveFromPath + + # This is needed for the environment variable changes to take effect. + DetailPrint "Broadcasting WM_WININICHANGE message..." + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=500 + +SectionEnd + +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${SecCore} $(DESC_SecCore) + !ifdef HAVE_GL + !insertmacro MUI_DESCRIPTION_TEXT ${SecOpenGL} $(DESC_SecOpenGL) + !endif + !ifdef HAVE_DX9 + !insertmacro MUI_DESCRIPTION_TEXT ${SecDirect3D9} $(DESC_SecDirect3D9) + !endif + !ifdef HAVE_OPENAL + !insertmacro MUI_DESCRIPTION_TEXT ${SecOpenAL} $(DESC_SecOpenAL) + !endif + !ifdef HAVE_FMOD + !insertmacro MUI_DESCRIPTION_TEXT ${SecFMOD} $(DESC_SecFMOD) + !endif + !ifdef HAVE_FFMPEG + !insertmacro MUI_DESCRIPTION_TEXT ${SecFFMpeg} $(DESC_SecFFMpeg) + !endif + !ifdef HAVE_BULLET + !insertmacro MUI_DESCRIPTION_TEXT ${SecBullet} $(DESC_SecBullet) + !endif + !ifdef HAVE_ODE + !insertmacro MUI_DESCRIPTION_TEXT ${SecODE} $(DESC_SecODE) + !endif + !ifdef HAVE_PHYSX + !insertmacro MUI_DESCRIPTION_TEXT ${SecPhysX} $(DESC_SecPhysX) + !endif + !ifdef HAVE_ROCKET + !insertmacro MUI_DESCRIPTION_TEXT ${SecRocket} $(DESC_SecRocket) + !endif + !insertmacro MUI_DESCRIPTION_TEXT ${SecTools} $(DESC_SecTools) + !insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings} $(DESC_SecPyBindings) + !insertmacro MUI_DESCRIPTION_TEXT ${SecPython} $(DESC_SecPython) + !insertmacro MUI_DESCRIPTION_TEXT ${SecHeadersLibs} $(DESC_SecHeadersLibs) + !insertmacro MUI_DESCRIPTION_TEXT ${SecSamples} $(DESC_SecSamples) + !ifdef HAVE_MAX_PLUGINS + !insertmacro MUI_DESCRIPTION_TEXT ${SecMaxPlugins} $(DESC_SecMaxPlugins) + !endif + !ifdef HAVE_MAYA_PLUGINS + !insertmacro MUI_DESCRIPTION_TEXT ${SecMayaPlugins} $(DESC_SecMayaPlugins) + !endif +!insertmacro MUI_FUNCTION_DESCRIPTION_END + +# --[ Utility Functions ]------------------------------------------------------ + +; From: http://nsis.sourceforge.net/archive/viewpage.php?pageid=91 +Function IsNT + Push $0 + ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + StrCmp $0 "" 0 IsNT_yes + ; we are not NT. + Pop $0 + Push 0 + Return + IsNT_yes: + ; NT!!! + Pop $0 + Push 1 +FunctionEnd + +; From: http://nsis.sourceforge.net/archive/viewpage.php?pageid=91 +Function un.IsNT + Push $0 + ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + StrCmp $0 "" 0 unIsNT_yes + ; we are not NT. + Pop $0 + Push 0 + Return + unIsNT_yes: + ; NT!!! + Pop $0 + Push 1 +FunctionEnd + +; From: http://nsis.sourceforge.net/archive/viewpage.php?pageid=91 +Function StrStr + Push $0 + Exch + Pop $0 ; $0 now have the string to find + Push $1 + Exch 2 + Pop $1 ; $1 now have the string to find in + Exch + Push $2 + Push $3 + Push $4 + Push $5 + StrCpy $2 -1 + StrLen $3 $0 + StrLen $4 $1 + IntOp $4 $4 - $3 + unStrStr_loop: + IntOp $2 $2 + 1 + IntCmp $2 $4 0 0 unStrStrReturn_notFound + StrCpy $5 $1 $3 $2 + StrCmp $5 $0 unStrStr_done unStrStr_loop + unStrStrReturn_notFound: + StrCpy $2 -1 + unStrStr_done: + Pop $5 + Pop $4 + Pop $3 + Exch $2 + Exch 2 + Pop $0 + Pop $1 +FunctionEnd + +; From: http://nsis.sourceforge.net/archive/viewpage.php?pageid=91 +Function un.StrStr + Push $0 + Exch + Pop $0 ; $0 now have the string to find + Push $1 + Exch 2 + Pop $1 ; $1 now have the string to find in + Exch + Push $2 + Push $3 + Push $4 + Push $5 + StrCpy $2 -1 + StrLen $3 $0 + StrLen $4 $1 + IntOp $4 $4 - $3 + unStrStr_loop: + IntOp $2 $2 + 1 + IntCmp $2 $4 0 0 unStrStrReturn_notFound + StrCpy $5 $1 $3 $2 + StrCmp $5 $0 unStrStr_done unStrStr_loop + unStrStrReturn_notFound: + StrCpy $2 -1 + unStrStr_done: + Pop $5 + Pop $4 + Pop $3 + Exch $2 + Exch 2 + Pop $0 + Pop $1 +FunctionEnd + +; Capitalizes the first letter of every word. +Function Capitalize + Exch $R0 + Push $0 + Push $1 + Push $2 + + StrCpy $0 0 + + capNext: + ; Grab the next character. + StrCpy $1 $R0 1 $0 + StrCmp $1 '' end + + ; Capitalize it. + ${StrFilter} '$1' '+eng' '' '' $1 + ${StrFilter} '$1' '+rus' '' '' $1 + + ; Splice it into the string. + StrCpy $2 $R0 $0 + IntOp $0 $0 + 1 + StrCpy $R0 $R0 '' $0 + StrCpy $R0 '$2$1$R0' + + ; Keep looping through the characters until we find a + ; delimiter or reach the end of the string. + loop: + StrCpy $1 $R0 1 $0 + IntOp $0 $0 + 1 + StrCmp $1 '' end + StrCmp $1 ' ' capNext + StrCmp $1 '_' capNext + StrCmp $1 '-' capNext + StrCmp $1 '(' capNext + StrCmp $1 '[' capNext + Goto loop + + end: + Pop $2 + Pop $1 + Pop $0 + Exch $R0 +FunctionEnd + +; From: http://nsis.sourceforge.net/archive/viewpage.php?pageid=91 +; Commentary and smarter ';' checking by Jon Parise +Function AddToPath + Exch $0 + Push $1 + Push $2 + Push $3 + Call IsNT + Pop $1 + + DetailPrint "Adding to PATH: $0" + + StrCmp $1 1 AddToPath_NT + ; We're not on NT, so modify the AUTOEXEC.BAT file. + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" a + FileSeek $1 0 END + GetFullPathName /SHORT $0 $0 + FileWrite $1 "$\r$\nSET PATH=%PATH%;$0$\r$\n" + FileClose $1 + Goto AddToPath_done + + AddToPath_NT: + ReadRegStr $1 HKCU "Environment" "PATH" + Call IsUserAdmin + Pop $3 + ; If this is an Admin user, use the System env. variable instead of the user's env. variable + StrCmp $3 1 0 +2 + ReadRegStr $1 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "PATH" + + ; If the PATH string is empty, jump over the mangling routines. + StrCmp $1 "" AddToPath_NTdoIt + + ; Pull off the last character of the PATH string. If it's a semicolon, + ; we don't need to add another one, so jump to the section where we + ; append the new PATH component(s). + StrCpy $2 $1 1 -1 + StrCmp $2 ";" AddToPath_NTAddPath AddToPath_NTAddSemi + + AddToPath_NTAddSemi: + StrCpy $1 "$1;" + Goto AddToPath_NTAddPath + AddToPath_NTAddPath: + StrCpy $0 "$1$0" + Goto AddToPath_NTdoIt + AddToPath_NTdoIt: + Call IsUserAdmin + Pop $3 + StrCmp $3 1 0 NotAdmin + WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "PATH" $0 + Goto AddToPath_done + + NotAdmin: + WriteRegExpandStr HKCU "Environment" "PATH" $0 + AddToPath_done: + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd + +; From: http://nsis.sourceforge.net/archive/viewpage.php?pageid=91 +Function RemoveFromPath + Exch $0 + Push $1 + Push $2 + Push $3 + Push $4 + Push $5 + Call IsNT + Pop $1 + + DetailPrint "Removing from PATH: $0" + + StrCmp $1 1 unRemoveFromPath_NT + ; Not on NT + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" r + GetTempFileName $4 + FileOpen $2 $4 w + GetFullPathName /SHORT $0 $0 + StrCpy $0 "SET PATH=%PATH%;$0" + SetRebootFlag true + Goto unRemoveFromPath_dosLoop + + unRemoveFromPath_dosLoop: + FileRead $1 $3 + StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoop + StrCmp $3 "$0$\n" unRemoveFromPath_dosLoop + StrCmp $3 "$0" unRemoveFromPath_dosLoop + StrCmp $3 "" unRemoveFromPath_dosLoopEnd + FileWrite $2 $3 + Goto unRemoveFromPath_dosLoop + + unRemoveFromPath_dosLoopEnd: + FileClose $2 + FileClose $1 + StrCpy $1 $WINDIR 2 + Delete "$1\autoexec.bat" + CopyFiles /SILENT $4 "$1\autoexec.bat" + Delete $4 + Goto unRemoveFromPath_done + + unRemoveFromPath_NT: + StrLen $2 $0 + Call IsUserAdmin + Pop $5 + StrCmp $5 1 0 NotAdmin + ReadRegStr $1 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "PATH" + Push $1 + Push $0 + Call StrStr ; Find $0 in $1 + Pop $0 ; pos of our dir + IntCmp $0 -1 unRemoveFromPath_done + ; else, it is in path + StrCpy $3 $1 $0 ; $3 now has the part of the path before our dir + IntOp $2 $2 + $0 ; $2 now contains the pos after our dir in the path (';') + IntOp $2 $2 + 1 ; $2 now containts the pos after our dir and the semicolon. + StrLen $0 $1 + StrCpy $1 $1 $0 $2 + StrCpy $3 "$3$1" + WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "PATH" $3 + Goto unRemoveFromPath_done + + + NotAdmin: + ReadRegStr $1 HKCU "Environment" "PATH" + Push $1 + Push $0 + Call StrStr ; Find $0 in $1 + Pop $0 ; pos of our dir + IntCmp $0 -1 unRemoveFromPath_done + ; else, it is in path + StrCpy $3 $1 $0 ; $3 now has the part of the path before our dir + IntOp $2 $2 + $0 ; $2 now contains the pos after our dir in the path (';') + IntOp $2 $2 + 1 ; $2 now containts the pos after our dir and the semicolon. + StrLen $0 $1 + StrCpy $1 $1 $0 $2 + StrCpy $3 "$3$1" + WriteRegExpandStr HKCU "Environment" "PATH" $3 + + unRemoveFromPath_done: + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd + +; From: http://nsis.sourceforge.net/archive/viewpage.php?pageid=91 +Function un.RemoveFromPath + Exch $0 + Push $1 + Push $2 + Push $3 + Push $4 + Push $5 + Call un.IsNT + Pop $1 + StrCmp $1 1 unRemoveFromPath_NT + ; Not on NT + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" r + GetTempFileName $4 + FileOpen $2 $4 w + GetFullPathName /SHORT $0 $0 + StrCpy $0 "SET PATH=%PATH%;$0" + SetRebootFlag true + Goto unRemoveFromPath_dosLoop + + unRemoveFromPath_dosLoop: + FileRead $1 $3 + StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoop + StrCmp $3 "$0$\n" unRemoveFromPath_dosLoop + StrCmp $3 "$0" unRemoveFromPath_dosLoop + StrCmp $3 "" unRemoveFromPath_dosLoopEnd + FileWrite $2 $3 + Goto unRemoveFromPath_dosLoop + + unRemoveFromPath_dosLoopEnd: + FileClose $2 + FileClose $1 + StrCpy $1 $WINDIR 2 + Delete "$1\autoexec.bat" + CopyFiles /SILENT $4 "$1\autoexec.bat" + Delete $4 + Goto unRemoveFromPath_done + + unRemoveFromPath_NT: + StrLen $2 $0 + Call un.IsUserAdmin + Pop $5 + StrCmp $5 1 0 NotAdmin + ReadRegStr $1 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "PATH" + Push $1 + Push $0 + Call un.StrStr ; Find $0 in $1 + Pop $0 ; pos of our dir + IntCmp $0 -1 unRemoveFromPath_done + ; else, it is in path + StrCpy $3 $1 $0 ; $3 now has the part of the path before our dir + IntOp $2 $2 + $0 ; $2 now contains the pos after our dir in the path (';') + IntOp $2 $2 + 1 ; $2 now containts the pos after our dir and the semicolon. + StrLen $0 $1 + StrCpy $1 $1 $0 $2 + StrCpy $3 "$3$1" + WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "PATH" $3 + Goto unRemoveFromPath_done + + + NotAdmin: + ReadRegStr $1 HKCU "Environment" "PATH" + Push $1 + Push $0 + Call un.StrStr ; Find $0 in $1 + Pop $0 ; pos of our dir + IntCmp $0 -1 unRemoveFromPath_done + ; else, it is in path + StrCpy $3 $1 $0 ; $3 now has the part of the path before our dir + IntOp $2 $2 + $0 ; $2 now contains the pos after our dir in the path (';') + IntOp $2 $2 + 1 ; $2 now containts the pos after our dir and the semicolon. + StrLen $0 $1 + StrCpy $1 $1 $0 $2 + StrCpy $3 "$3$1" + WriteRegExpandStr HKCU "Environment" "PATH" $3 + + unRemoveFromPath_done: + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd + +; From: http://nsis.sourceforge.net/archive/nsisweb.php?page=329&instances=0,11 +; Localized by Ben Johnson (bkj@andrew.cmu.edu) +Function IsUserAdmin + Push $0 + Push $1 + Push $2 + Push $3 + Call IsNT + Pop $1 + + ClearErrors + UserInfo::GetName + ;IfErrors Win9x + Pop $2 + UserInfo::GetAccountType + Pop $3 + + ; Compare results of IsNT with "1" + StrCmp $1 1 0 NotNT + ;This is NT + + + StrCmp $3 "Admin" 0 NotAdmin + ; Observation: I get here when running Win98SE. (Lilla) + ; The functions UserInfo.dll looks for are there on Win98 too, + ; but just don't work. So UserInfo.dll, knowing that admin isn't required + ; on Win98, returns admin anyway. (per kichik) + ; MessageBox MB_OK 'User "$R1" is in the Administrators group' + Pop $3 + Pop $2 + Pop $1 + Pop $0 + + Push 1 + Return + + NotAdmin: + ; You should still check for an empty string because the functions + ; UserInfo.dll looks for may not be present on Windows 95. (per kichik) + + #StrCmp $2 "" Win9x + #StrCpy $0 0 + ;MessageBox MB_OK 'User "$2" is in the "$3" group' + Pop $3 + Pop $2 + Pop $1 + Pop $0 + + Push 0 + Return + + ;Because we use IsNT, this is redundant. + #Win9x: + # ; comment/message below is by UserInfo.nsi author: + # ; This one means you don't need to care about admin or + # ; not admin because Windows 9x doesn't either + # ;MessageBox MB_OK "Error! This DLL can't run under Windows 9x!" + # StrCpy $0 0 + + NotNT: + ;We are not NT + ;Win9x doesn't have "admin" users. + ;Let the user do whatever. + Pop $3 + Pop $2 + Pop $1 + Pop $0 + + Push 1 + +FunctionEnd + +Function un.IsUserAdmin + Push $0 + Push $1 + Push $2 + Push $3 + Call un.IsNT + Pop $1 + + ClearErrors + UserInfo::GetName + ;IfErrors Win9x + Pop $2 + UserInfo::GetAccountType + Pop $3 + + ; Compare results of IsNT with "1" + StrCmp $1 1 0 NotNT + ;This is NT + + + StrCmp $3 "Admin" 0 NotAdmin + ; Observation: I get here when running Win98SE. (Lilla) + ; The functions UserInfo.dll looks for are there on Win98 too, + ; but just don't work. So UserInfo.dll, knowing that admin isn't required + ; on Win98, returns admin anyway. (per kichik) + ; MessageBox MB_OK 'User "$R1" is in the Administrators group' + Pop $3 + Pop $2 + Pop $1 + Pop $0 + + Push 1 + Return + + NotAdmin: + ; You should still check for an empty string because the functions + ; UserInfo.dll looks for may not be present on Windows 95. (per kichik) + + #StrCmp $2 "" Win9x + #StrCpy $0 0 + ;MessageBox MB_OK 'User "$2" is in the "$3" group' + Pop $3 + Pop $2 + Pop $1 + Pop $0 + + Push 0 + Return + + ;Because we use IsNT, this is redundant. + #Win9x: + # ; comment/message below is by UserInfo.nsi author: + # ; This one means you don't need to care about admin or + # ; not admin because Windows 9x doesn't either + # ;MessageBox MB_OK "Error! This DLL can't run under Windows 9x!" + # StrCpy $0 0 + + NotNT: + ;We are not NT + ;Win9x doesn't have "admin" users. + ;Let the user do whatever. + Pop $3 + Pop $2 + Pop $1 + Pop $0 + + Push 1 + +FunctionEnd + +Function StrRep + + ;Written by dirtydingus 2003-02-20 04:30:09 + ; USAGE + ;Push String to do replacement in (haystack) + ;Push String to replace (needle) + ;Push Replacement + ;Call StrRep + ;Pop $R0 result + ;StrCpy $Result STR $R0 + + Exch $R4 ; $R4 = Replacement String + Exch + Exch $R3 ; $R3 = String to replace (needle) + Exch 2 + Exch $R1 ; $R1 = String to do replacement in (haystack) + Push $R2 ; Replaced haystack + Push $R5 ; Len (needle) + Push $R6 ; len (haystack) + Push $R7 ; Scratch reg + StrCpy $R2 "" + StrLen $R5 $R3 + StrLen $R6 $R1 +loop: + StrCpy $R7 $R1 $R5 + StrCmp $R7 $R3 found + StrCpy $R7 $R1 1 ; - optimization can be removed if U know len needle=1 + StrCpy $R2 "$R2$R7" + StrCpy $R1 $R1 $R6 1 + StrCmp $R1 "" done loop +found: + StrCpy $R2 "$R2$R4" + StrCpy $R1 $R1 $R6 $R5 + StrCmp $R1 "" done loop +done: + StrCpy $R3 $R2 + Pop $R7 + Pop $R6 + Pop $R5 + Pop $R2 + Pop $R1 + Pop $R4 + Exch $R3 + +FunctionEnd diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index f07093c740..3ddb09d55e 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -6173,7 +6173,7 @@ except: # ########################################################################################## -def MakeInstallerNSIS(file, fullname, smdirectory, installdir): +def MakeInstallerNSIS(file, title, installdir): if (os.path.isfile(file)): os.remove(file) elif (os.path.isdir(file)): @@ -6201,7 +6201,7 @@ def MakeInstallerNSIS(file, fullname, smdirectory, installdir): shutil.move("direct\\src\\plugin_installer\\p3d-setup.exe", file) return - print("Building "+fullname+" installer. This can take up to an hour.") + print("Building "+title+" installer. This can take up to an hour.") if (COMPRESSOR != "lzma"): print("Note: you are using zlib, which is faster, but lzma gives better compression.") if (os.path.exists("nsis-output.exe")): @@ -6212,19 +6212,13 @@ def MakeInstallerNSIS(file, fullname, smdirectory, installdir): nsis_defs = { 'COMPRESSOR' : COMPRESSOR, - 'NAME' : fullname, - 'SMDIRECTORY' : smdirectory, + 'TITLE' : title, 'INSTALLDIR' : installdir, 'OUTFILE' : os.path.join(psource, 'nsis-output.exe'), 'LICENSE' : os.path.join(panda, 'LICENSE'), - 'LANGUAGE' : "English", - 'RUNTEXT' : "Visit the Panda Manual", - 'IBITMAP' : "panda-install.bmp", - 'UBITMAP' : "panda-install.bmp", - 'PANDA' : panda, + 'BUILT' : panda, + 'SOURCE' : psource, 'PYVER' : SDK["PYTHONVERSION"][6:9], - 'PANDACONF' : os.path.join(panda, 'etc'), - 'PSOURCE' : psource, 'PYEXTRAS' : os.path.join(os.path.abspath(GetThirdpartyBase()), 'win-extras'), 'REGVIEW' : regview, } @@ -6238,7 +6232,7 @@ def MakeInstallerNSIS(file, fullname, smdirectory, installdir): for item in nsis_defs.items(): cmd += ' -D%s="%s"' % item - cmd += ' "%s"' % (os.path.join(psource, 'direct', 'src', 'directscripts', 'packpanda.nsi')) + cmd += ' "%s"' % (os.path.join(psource, 'makepanda', 'installer.nsi')) oscmd(cmd) os.rename("nsis-output.exe", file) @@ -6763,14 +6757,14 @@ try: if (GetOptimize() <= 2): dbg = "-dbg" if GetTargetArch() == 'x64': if (RUNTIME): - MakeInstallerNSIS("Panda3D-Runtime-"+VERSION+dbg+"-x64.exe", "Panda3D", "Panda3D "+VERSION, "C:\\Panda3D-"+VERSION+"-x64") + MakeInstallerNSIS("Panda3D-Runtime-"+VERSION+dbg+"-x64.exe", "Panda3D "+VERSION, "C:\\Panda3D-"+VERSION+"-x64") else: - MakeInstallerNSIS("Panda3D-"+VERSION+dbg+"-x64.exe", "Panda3D", "Panda3D "+VERSION, "C:\\Panda3D-"+VERSION+"-x64") + MakeInstallerNSIS("Panda3D-"+VERSION+dbg+"-x64.exe", "Panda3D SDK "+VERSION, "C:\\Panda3D-"+VERSION+"-x64") else: if (RUNTIME): - MakeInstallerNSIS("Panda3D-Runtime-"+VERSION+dbg+".exe", "Panda3D", "Panda3D "+VERSION, "C:\\Panda3D-"+VERSION) + MakeInstallerNSIS("Panda3D-Runtime-"+VERSION+dbg+".exe", "Panda3D "+VERSION, "C:\\Panda3D-"+VERSION) else: - MakeInstallerNSIS("Panda3D-"+VERSION+dbg+".exe", "Panda3D", "Panda3D "+VERSION, "C:\\Panda3D-"+VERSION) + MakeInstallerNSIS("Panda3D-"+VERSION+dbg+".exe", "Panda3D SDK "+VERSION, "C:\\Panda3D-"+VERSION) elif (target == 'linux'): MakeInstallerLinux() elif (target == 'darwin'): diff --git a/direct/src/directscripts/panda-install.bmp b/makepanda/panda-install.bmp similarity index 100% rename from direct/src/directscripts/panda-install.bmp rename to makepanda/panda-install.bmp diff --git a/panda/src/pgraph/loader.cxx b/panda/src/pgraph/loader.cxx index 440939b945..1c3a000988 100644 --- a/panda/src/pgraph/loader.cxx +++ b/panda/src/pgraph/loader.cxx @@ -343,11 +343,11 @@ try_load_file(const Filename &pathname, const LoaderOptions &options, return result; } } - } - if (loader_cat.is_debug()) { - loader_cat.debug() - << "Model " << pathname << " not found in cache.\n"; + if (loader_cat.is_debug()) { + loader_cat.debug() + << "Model " << pathname << " not found in cache.\n"; + } } bool cache_only = (options.get_flags() & LoaderOptions::LF_cache_only) != 0; diff --git a/panda/src/putil/bamCache.cxx b/panda/src/putil/bamCache.cxx index daf64f40c0..7616350e07 100644 --- a/panda/src/putil/bamCache.cxx +++ b/panda/src/putil/bamCache.cxx @@ -43,7 +43,7 @@ BamCache() : _index_stale_since(0) { ConfigVariableFilename model_cache_dir - ("model-cache-dir", Filename(), + ("model-cache-dir", Filename(), PRC_DESC("The full path to a directory, local to this computer, in which " "model and texture files will be cached on load. If a directory " "name is specified here, files may be loaded from the cache " @@ -51,7 +51,7 @@ BamCache() : "especially if you are loading egg files instead of bam files, " "or if you are loading models from a shared network drive. " "If this is the empty string, no cache will be used.")); - + ConfigVariableInt model_cache_flush ("model-cache-flush", 30, PRC_DESC("This is the amount of time, in seconds, between automatic " @@ -138,7 +138,7 @@ set_root(const Filename &root) { //////////////////////////////////////////////////////////////////// // Function: BamCache::lookup // Access: Published -// Description: Looks up a file in the cache. +// Description: Looks up a file in the cache. // // If the file is cacheable, then regardless of whether // the file is found in the cache or not, this returns a @@ -163,7 +163,7 @@ lookup(const Filename &source_filename, const string &cache_extension) { consider_flush_index(); VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); - + Filename source_pathname(source_filename); source_pathname.make_absolute(vfs->get_cwd()); @@ -200,7 +200,7 @@ store(BamCacheRecord *record) { if (_read_only) { return false; } - + consider_flush_index(); #ifndef NDEBUG @@ -231,7 +231,7 @@ store(BamCacheRecord *record) { emergency_read_only(); return false; } - + if (!dout.write_header(_bam_header)) { util_cat.error() << "Unable to write to " << temp_pathname << "\n"; @@ -247,7 +247,7 @@ store(BamCacheRecord *record) { vfs->delete_file(temp_pathname); return false; } - + TypeRegistry *type_registry = TypeRegistry::ptr(); TypeHandle texture_type = type_registry->find_type("Texture"); if (record->get_data()->is_of_type(texture_type)) { @@ -257,14 +257,14 @@ store(BamCacheRecord *record) { // Any other kinds of objects write texture references. writer.set_file_texture_mode(BamWriter::BTM_fullpath); } - + if (!writer.write_object(record)) { util_cat.error() << "Unable to write object to " << temp_pathname << "\n"; vfs->delete_file(temp_pathname); return false; } - + if (!writer.write_object(record->get_data())) { util_cat.error() << "Unable to write object data to " << temp_pathname << "\n"; @@ -354,7 +354,7 @@ flush_index() { emergency_read_only(); return; } - + // Now atomically write the name of this index file to the index // reference file. VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); @@ -385,6 +385,16 @@ flush_index() { check_cache_size(); } +//////////////////////////////////////////////////////////////////// +// Function: BamCache::list_index +// Access: Published +// Description: Writes the contents of the index to standard output. +//////////////////////////////////////////////////////////////////// +void BamCache:: +list_index(ostream &out, int indent_level) const { + _index->write(out, indent_level); +} + //////////////////////////////////////////////////////////////////// // Function: BamCache::read_index // Access: Private diff --git a/panda/src/putil/bamCache.h b/panda/src/putil/bamCache.h index 62e055764f..beab547935 100644 --- a/panda/src/putil/bamCache.h +++ b/panda/src/putil/bamCache.h @@ -73,13 +73,15 @@ PUBLISHED: INLINE void set_read_only(bool ro); INLINE bool get_read_only() const; - PT(BamCacheRecord) lookup(const Filename &source_filename, + PT(BamCacheRecord) lookup(const Filename &source_filename, const string &cache_extension); bool store(BamCacheRecord *record); void consider_flush_index(); void flush_index(); - + + void list_index(ostream &out, int indent_level = 0) const; + INLINE static BamCache *get_global_ptr(); private: @@ -96,7 +98,7 @@ private: void check_cache_size(); void emergency_read_only(); - + static BamCacheIndex *do_read_index(const Filename &index_pathname); static bool do_write_index(const Filename &index_pathname, const BamCacheIndex *index); @@ -105,7 +107,7 @@ private: PT(BamCacheRecord) read_record(const Filename &source_pathname, const Filename &cache_filename, int pass); - static PT(BamCacheRecord) do_read_record(const Filename &cache_pathname, + static PT(BamCacheRecord) do_read_record(const Filename &cache_pathname, bool read_data); static string hash_filename(const string &filename); From 4d2dcdcef757b4992b805efb21579b5cf5df8f04 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 11 Feb 2015 21:41:48 +0100 Subject: [PATCH 02/32] Fix OpenGL ES compiler errors --- panda/src/egldisplay/eglGraphicsBuffer.cxx | 14 +- panda/src/egldisplay/eglGraphicsBuffer.h | 2 +- panda/src/egldisplay/eglGraphicsPixmap.cxx | 14 +- panda/src/egldisplay/eglGraphicsPixmap.h | 4 +- panda/src/gles2gsg/gles2gsg.h | 25 ++- panda/src/glesgsg/glesgsg.h | 3 + panda/src/glstuff/glGraphicsBuffer_src.cxx | 2 +- .../src/glstuff/glGraphicsStateGuardian_src.I | 7 +- .../glstuff/glGraphicsStateGuardian_src.cxx | 174 ++++++++++-------- panda/src/glstuff/glSamplerContext_src.cxx | 4 + panda/src/glstuff/glSamplerContext_src.h | 4 + panda/src/glstuff/glShaderContext_src.cxx | 10 +- panda/src/glstuff/glmisc_src.cxx | 2 + 13 files changed, 150 insertions(+), 115 deletions(-) diff --git a/panda/src/egldisplay/eglGraphicsBuffer.cxx b/panda/src/egldisplay/eglGraphicsBuffer.cxx index b34ca33e07..b18781aa97 100644 --- a/panda/src/egldisplay/eglGraphicsBuffer.cxx +++ b/panda/src/egldisplay/eglGraphicsBuffer.cxx @@ -1,5 +1,5 @@ // Filename: eglGraphicsBuffer.cxx -// Created by: pro-rsoft (13Jun09) +// Created by: rdb (13Jun09) // //////////////////////////////////////////////////////////////////// // @@ -28,7 +28,7 @@ TypeHandle eglGraphicsBuffer::_type_handle; // Description: //////////////////////////////////////////////////////////////////// eglGraphicsBuffer:: -eglGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe, +eglGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe, const string &name, const FrameBufferProperties &fb_prop, const WindowProperties &win_prop, @@ -187,7 +187,7 @@ open_buffer() { _gsg = eglgsg; } } - + if (eglgsg->_fbconfig == None) { // If we didn't use an fbconfig to create the GSG, we can't create // a PBuffer. @@ -195,11 +195,11 @@ open_buffer() { } int attrib_list[] = { - EGL_WIDTH, _x_size, - EGL_HEIGHT, _y_size, + EGL_WIDTH, _size.get_x(), + EGL_HEIGHT, _size.get_y(), EGL_NONE }; - + _pbuffer = eglCreatePbufferSurface(eglgsg->_egl_display, eglgsg->_fbconfig, attrib_list); if (_pbuffer == EGL_NO_SURFACE) { @@ -224,7 +224,7 @@ open_buffer() { return false; } _fb_properties = eglgsg->get_fb_properties(); - + _is_valid = true; return true; } diff --git a/panda/src/egldisplay/eglGraphicsBuffer.h b/panda/src/egldisplay/eglGraphicsBuffer.h index 155a9aba2f..a1f2c92b69 100644 --- a/panda/src/egldisplay/eglGraphicsBuffer.h +++ b/panda/src/egldisplay/eglGraphicsBuffer.h @@ -1,5 +1,5 @@ // Filename: eglGraphicsBuffer.h -// Created by: pro-rsoft (13Jun09) +// Created by: rdb (13Jun09) // //////////////////////////////////////////////////////////////////// // diff --git a/panda/src/egldisplay/eglGraphicsPixmap.cxx b/panda/src/egldisplay/eglGraphicsPixmap.cxx index 46abe8a34b..46e2e20c90 100644 --- a/panda/src/egldisplay/eglGraphicsPixmap.cxx +++ b/panda/src/egldisplay/eglGraphicsPixmap.cxx @@ -1,5 +1,5 @@ // Filename: eglGraphicsPixmap.cxx -// Created by: pro-rsoft (13Jun09) +// Created by: rdb (13Jun09) // //////////////////////////////////////////////////////////////////// // @@ -29,7 +29,7 @@ TypeHandle eglGraphicsPixmap::_type_handle; // Description: //////////////////////////////////////////////////////////////////// eglGraphicsPixmap:: -eglGraphicsPixmap(GraphicsEngine *engine, GraphicsPipe *pipe, +eglGraphicsPixmap(GraphicsEngine *engine, GraphicsPipe *pipe, const string &name, const FrameBufferProperties &fb_prop, const WindowProperties &win_prop, @@ -105,7 +105,7 @@ begin_frame(FrameMode mode, Thread *current_thread) { } clear_cube_map_selection(); } - + _gsg->set_current_properties(&get_fb_properties()); return _gsg->begin_frame(current_thread); } @@ -195,7 +195,7 @@ open_buffer() { _gsg = eglgsg; } } - + if (eglgsg->_fbconfig == None) { // If we didn't use an fbconfig to create the GSG, we can't create // a PBuffer. @@ -221,8 +221,8 @@ open_buffer() { } } - _x_pixmap = XCreatePixmap(_display, _drawable, - _x_size, _y_size, visual_info->depth); + _x_pixmap = XCreatePixmap(_display, _drawable, + _size.get_x(), _size.get_y(), visual_info->depth); if (_x_pixmap == None) { egldisplay_cat.error() << "Failed to create X pixmap.\n"; @@ -253,7 +253,7 @@ open_buffer() { return false; } _fb_properties = eglgsg->get_fb_properties(); - + _is_valid = true; return true; } diff --git a/panda/src/egldisplay/eglGraphicsPixmap.h b/panda/src/egldisplay/eglGraphicsPixmap.h index 09aab1dbb8..e1ca988965 100644 --- a/panda/src/egldisplay/eglGraphicsPixmap.h +++ b/panda/src/egldisplay/eglGraphicsPixmap.h @@ -1,5 +1,5 @@ // Filename: eglGraphicsPixmap.h -// Created by: pro-rsoft (13Jun09) +// Created by: rdb (13Jun09) // //////////////////////////////////////////////////////////////////// // @@ -29,7 +29,7 @@ //////////////////////////////////////////////////////////////////// class eglGraphicsPixmap : public GraphicsBuffer { public: - eglGraphicsPixmap(GraphicsEngine *engine, GraphicsPipe *pipe, + eglGraphicsPixmap(GraphicsEngine *engine, GraphicsPipe *pipe, const string &name, const FrameBufferProperties &fb_prop, const WindowProperties &win_prop, diff --git a/panda/src/gles2gsg/gles2gsg.h b/panda/src/gles2gsg/gles2gsg.h index cd5444c7ef..d06c160e02 100644 --- a/panda/src/gles2gsg/gles2gsg.h +++ b/panda/src/gles2gsg/gles2gsg.h @@ -57,7 +57,7 @@ // #include #endif -#include "panda_esgl2ext.h" +#include "panda_esgl2ext.h" // This helps to keep the source clean of hundreds of #ifdefs. typedef char GLchar; @@ -100,20 +100,19 @@ typedef char GLchar; #define GL_RGBA16F GL_RGBA16F_EXT #define GL_RGB32F GL_RGB32F_EXT #define GL_RGBA32F GL_RGBA32F_EXT -#define GL_DEBUG_SEVERITY_HIGH GL_DEBUG_SEVERITY_HIGH_KHR -#define GL_DEBUG_SEVERITY_MEDIUM GL_DEBUG_SEVERITY_MEDIUM_KHR -#define GL_DEBUG_SEVERITY_LOW GL_DEBUG_SEVERITY_LOW_KHR -#define GL_DEBUG_SEVERITY_NOTIFICATION GL_DEBUG_SEVERITY_NOTIFICATION_KHR -#define GL_DEBUG_OUTPUT_SYNCHRONOUS GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR -#define GL_FRAMEBUFFER_SRGB GL_FRAMEBUFFER_SRGB_EXT #define GL_SRGB GL_SRGB_EXT #define GL_SRGB_ALPHA GL_SRGB_ALPHA_EXT -#define GL_SRGB8 GL_SRGB8_EXT -#define GL_SRGB8_ALPHA GL_SRGB8_ALPHA_EXT -#define GL_SLUMINANCE GL_SLUMINANCE_NV -#define GL_SLUMINANCE_ALPHA GL_SLUMINANCE_ALPHA_NV -#define GL_SLUMINANCE8 GL_SLUMINANCE8_NV -#define GL_SLUMINANCE8_ALPHA GL_SLUMINANCE8_ALPHA_NV +#define GL_SRGB8_ALPHA8 GL_SRGB8_ALPHA8_EXT +#define GL_RGBA8 GL_RGBA8_OES +#define GL_R8 GL_R8_EXT +#define GL_RG8 GL_RG8_EXT +#define GL_ALPHA8 GL_ALPHA8_OES +#define GL_LUMINANCE8 GL_LUMINANCE8_OES +#define GL_LUMINANCE8_ALPHA8 GL_LUMINANCE8_ALPHA8_EXT +#define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_EXT +#define GL_R32F GL_R32F_EXT +#define GL_RG32F GL_RG32F_EXT +#define GL_RGB8 GL_RGB8_OES #undef SUPPORT_IMMEDIATE_MODE #define APIENTRY diff --git a/panda/src/glesgsg/glesgsg.h b/panda/src/glesgsg/glesgsg.h index 485bc0dacc..9a3825c5dd 100644 --- a/panda/src/glesgsg/glesgsg.h +++ b/panda/src/glesgsg/glesgsg.h @@ -115,6 +115,9 @@ #define GL_RGBA16F GL_RGBA16F_EXT #define GL_RGB32F GL_RGB32F_EXT #define GL_RGBA32F GL_RGBA32F_EXT +#define GL_ALPHA8 GL_ALPHA8_EXT +#define GL_LUMINANCE8 GL_LUMINANCE8_EXT +#define GL_LUMINANCE8_ALPHA8 GL_LUMINANCE8_ALPHA8_EXT #undef SUPPORT_IMMEDIATE_MODE #define APIENTRY diff --git a/panda/src/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index 30b39c55ba..245fedb579 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.cxx +++ b/panda/src/glstuff/glGraphicsBuffer_src.cxx @@ -1674,7 +1674,7 @@ resolve_multisamples() { GL_NEAREST); } // Now handle the other color buffers. -#ifndef OPENGLES_1 +#ifndef OPENGLES int next = GL_COLOR_ATTACHMENT1_EXT; if (_fb_properties.is_stereo()) { glReadBuffer(next); diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.I b/panda/src/glstuff/glGraphicsStateGuardian_src.I index 2831d5a3d3..6d5248acf2 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.I +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.I @@ -745,9 +745,12 @@ call_glTexParameterfv(GLenum target, GLenum pname, const LVecBase4 &value) { // Access: Public // Description: Convert index to gl light id //////////////////////////////////////////////////////////////////// -INLINE GLenum CLP(GraphicsStateGuardian)::get_light_id(int index) const { +INLINE GLenum CLP(GraphicsStateGuardian):: +get_light_id(int index) const { #ifndef OPENGLES_2 return GL_LIGHT0 + index; +#else + return 0; #endif } @@ -760,6 +763,8 @@ INLINE GLenum CLP(GraphicsStateGuardian):: get_clip_plane_id(int index) const { #ifndef OPENGLES_2 return GL_CLIP_PLANE0 + index; +#else + return 0; #endif } diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 0d0c019b65..8845d69f61 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -127,16 +127,16 @@ null_glBlendColor(GLclampf, GLclampf, GLclampf, GLclampf) { // a fixed-function pipeline. // This default shader just outputs a red color, telling // the user that something went wrong. -CPT(Shader::ShaderFile) default_shader_name = new Shader::ShaderFile("default-shader"); -CPT(Shader::ShaderFile) default_shader_body = new Shader::ShaderFile("\ -uniform mediump mat4 p3d_ModelViewProjectionMatrix;\ -attribute highp vec4 p3d_Vertex;\ -void main(void) {\ - gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;\ -}\n", -"void main(void) {\ - gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\ -}\n", "", "", ""); +static const string default_vshader = + "uniform mediump mat4 p3d_ModelViewProjectionMatrix;\n" + "attribute highp vec4 p3d_Vertex;\n" + "void main(void) {\n" + " gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;\n" + "}\n"; +static const string default_fshader = + "void main(void) {\n" + " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" + "}\n"; #endif @@ -1370,7 +1370,7 @@ reset() { // if it failed to compile. This default shader just outputs // a red color, indicating that something went wrong. if (_default_shader == NULL) { - _default_shader = new Shader(default_shader_name, default_shader_body, Shader::SL_GLSL); + _default_shader = Shader::load(Shader::SL_GLSL, default_vshader, default_fshader); } #endif @@ -1915,6 +1915,8 @@ reset() { } _supports_sampler_objects = false; + +#ifndef OPENGLES if (gl_support_sampler_objects && ((is_at_least_gl_version(3, 3) || has_extension("GL_ARB_sampler_objects")))) { _glGenSamplers = (PFNGLGENSAMPLERSPROC) get_extension_func("glGenSamplers"); @@ -1935,6 +1937,7 @@ reset() { _supports_sampler_objects = true; } } +#endif // OPENGLES // Check availability of multi-bind functions. _supports_multi_bind = false; @@ -1944,10 +1947,12 @@ reset() { _glBindImageTextures = (PFNGLBINDIMAGETEXTURESPROC) get_extension_func("glBindImageTextures"); +#ifndef OPENGLES if (_supports_sampler_objects) { _glBindSamplers = (PFNGLBINDSAMPLERSPROC) get_extension_func("glBindSamplers"); } +#endif // OPENGLES if (_glBindTextures != NULL && _glBindImageTextures != NULL) { _supports_multi_bind = true; @@ -2011,14 +2016,18 @@ reset() { _supports_stencil_wrap = has_extension("GL_EXT_stencil_wrap") || has_extension("GL_OES_stencil_wrap"); - _supports_two_sided_stencil = has_extension("GL_EXT_stencil_two_side"); - if (_supports_two_sided_stencil) { + + + _supports_two_sided_stencil = false; +#ifndef OPENGLES + if (has_extension("GL_EXT_stencil_two_side")) { _glActiveStencilFaceEXT = (PFNGLACTIVESTENCILFACEEXTPROC) get_extension_func("glActiveStencilFaceEXT"); - } - else { + _supports_two_sided_stencil = true; + } else { _glActiveStencilFaceEXT = 0; } +#endif #ifndef OPENGLES // Some drivers expose one, some expose the other. ARB seems to be the newer one. @@ -2618,9 +2627,11 @@ clear_before_callback() { // Clear the bound sampler object, so that we do not inadvertently // override the callback's desired sampler settings. +#ifndef OPENGLES if (_supports_sampler_objects) { _glBindSampler(0, 0); } +#endif } //////////////////////////////////////////////////////////////////// @@ -2761,7 +2772,7 @@ begin_frame(Thread *current_thread) { }*/ #endif -#ifndef OPENGLES_1 +#ifndef OPENGLES if (_current_properties->get_srgb_color()) { glEnable(GL_FRAMEBUFFER_SRGB); } @@ -2819,7 +2830,7 @@ void CLP(GraphicsStateGuardian):: end_frame(Thread *current_thread) { report_my_gl_errors(); -#ifndef OPENGLES_1 +#ifndef OPENGLES if (_current_properties->get_srgb_color()) { glDisable(GL_FRAMEBUFFER_SRGB); } @@ -4521,8 +4532,10 @@ prepare_sampler(const SamplerState &sampler) { //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: release_sampler(SamplerContext *sc) { +#ifndef OPENGLES CLP(SamplerContext) *gsc = DCAST(CLP(SamplerContext), sc); delete gsc; +#endif } //////////////////////////////////////////////////////////////////// @@ -5205,7 +5218,7 @@ make_geom_munger(const RenderState *state, Thread *current_thread) { // from the camera plane. The point is assumed to be // in the GSG's internal coordinate system. //////////////////////////////////////////////////////////////////// -PN_stdfloat GLGraphicsStateGuardian:: +PN_stdfloat CLP(GraphicsStateGuardian):: compute_distance_to(const LPoint3 &point) const { return -point[2]; } @@ -7447,7 +7460,7 @@ get_external_image_format(Texture *tex) const { break; case Texture::CM_dxt1: -#ifndef OPENGLES_1 +#ifndef OPENGLES if (format == Texture::F_srgb_alpha) { return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; } else if (format == Texture::F_srgb) { @@ -7484,13 +7497,13 @@ get_external_image_format(Texture *tex) const { #else case Texture::CM_pvr1_2bpp: -#ifndef OPENGLES_1 +#ifndef OPENGLES if (format == Texture::F_srgb_alpha) { return GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT; } else if (format == Texture::F_srgb) { return GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT; } else -#endif // OPENGLES_1 +#endif // OPENGLES if (Texture::has_alpha(format)) { return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; } else { @@ -7498,13 +7511,13 @@ get_external_image_format(Texture *tex) const { } case Texture::CM_pvr1_4bpp: -#ifndef OPENGLES_1 +#ifndef OPENGLES if (format == Texture::F_srgb_alpha) { return GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT; } else if (format == Texture::F_srgb) { return GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT; } else -#endif // OPENGLES_1 +#endif // OPENGLES if (Texture::has_alpha(format)) { return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; } else { @@ -7762,7 +7775,7 @@ get_internal_image_format(Texture *tex, bool force_sized) const { #endif case Texture::CM_dxt1: -#ifndef OPENGLES_1 +#ifndef OPENGLES if (format == Texture::F_srgb_alpha) { return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; } else if (format == Texture::F_srgb) { @@ -7798,13 +7811,6 @@ get_internal_image_format(Texture *tex, bool force_sized) const { } #else case Texture::CM_pvr1_2bpp: -#ifndef OPENGLES_1 - if (format == Texture::F_srgb_alpha) { - return GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT; - } else if (format == Texture::F_srgb) { - return GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT; - } else -#endif // OPENGLES_1 if (Texture::has_alpha(format)) { return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; } else { @@ -7812,13 +7818,6 @@ get_internal_image_format(Texture *tex, bool force_sized) const { } case Texture::CM_pvr1_4bpp: -#ifndef OPENGLES_1 - if (format == Texture::F_srgb_alpha) { - return GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT; - } else if (format == Texture::F_srgb) { - return GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT; - } else -#endif // OPENGLES_1 if (Texture::has_alpha(format)) { return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; } else { @@ -7843,7 +7842,7 @@ get_internal_image_format(Texture *tex, bool force_sized) const { case Texture::F_depth_stencil: if (_supports_depth_stencil) { -#ifndef OPENGLES_1 +#ifndef OPENGLES if (tex->get_component_type() == Texture::T_float) { return GL_DEPTH32F_STENCIL8; } else @@ -7903,7 +7902,10 @@ get_internal_image_format(Texture *tex, bool force_sized) const { #ifndef OPENGLES_1 if (tex->get_component_type() == Texture::T_float) { return GL_RGBA16F; - } else if (tex->get_component_type() == Texture::T_unsigned_short) { + } else +#endif +#ifndef OPENGLES + if (tex->get_component_type() == Texture::T_unsigned_short) { return GL_RGBA16; } else #endif @@ -7949,7 +7951,7 @@ get_internal_image_format(Texture *tex, bool force_sized) const { case Texture::F_rgba12: return GL_RGBA12; #endif // OPENGLES -#ifndef OPENGLES_1 +#ifndef OPENGLES case Texture::F_rgba16: if (tex->get_component_type() == Texture::T_float) { return GL_RGBA16F; @@ -8040,26 +8042,36 @@ get_internal_image_format(Texture *tex, bool force_sized) const { return force_sized ? GL_ALPHA8 : GL_ALPHA; case Texture::F_luminance: +#ifndef OPENGLES if (tex->get_component_type() == Texture::T_float) { return GL_LUMINANCE16F_ARB; } else if (tex->get_component_type() == Texture::T_unsigned_short) { return GL_LUMINANCE16; - } else { + } else +#endif // OPENGLES + { return force_sized ? GL_LUMINANCE8 : GL_LUMINANCE; } case Texture::F_luminance_alpha: case Texture::F_luminance_alphamask: +#ifndef OPENGLES if (tex->get_component_type() == Texture::T_float || tex->get_component_type() == Texture::T_unsigned_short) { return GL_LUMINANCE_ALPHA16F_ARB; - } else { + } else +#endif // OPENGLES + { return force_sized ? GL_LUMINANCE8_ALPHA8 : GL_LUMINANCE_ALPHA; } #ifndef OPENGLES_1 case Texture::F_srgb: +#ifndef OPENGLES return GL_SRGB8; +#endif case Texture::F_srgb_alpha: return GL_SRGB8_ALPHA8; +#endif +#ifndef OPENGLES case Texture::F_sluminance: return GL_SLUMINANCE8; case Texture::F_sluminance_alpha: @@ -9043,7 +9055,7 @@ set_state_and_transform(const RenderState *target, //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: free_pointers() { -#ifdef HAVE_CG +#if defined(HAVE_CG) && !defined(OPENGLES) if (_cg_context != 0) { cgDestroyContext(_cg_context); _cg_context = 0; @@ -10081,6 +10093,7 @@ bool CLP(GraphicsStateGuardian):: apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc) { CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); +#ifndef OPENGLES if (_supports_sampler_objects) { // We support sampler objects. Prepare the sampler object and // bind it to the indicated texture unit. @@ -10097,7 +10110,9 @@ apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc) { << "bind " << unit << " " << sampler << "\n"; } - } else { + } else +#endif // OPENGLES + { // We don't support sampler objects. We'll have to bind the // texture and change the texture parameters if they don't match. if (gtc->_active_sampler != sampler) { @@ -10678,6 +10693,7 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, if (tex->has_clear_color()) { // The texture has a clear color, so we should fill this mipmap // level to a solid color. +#ifndef OPENGLES if (_supports_clear_texture) { // We can do that with the convenient glClearTexImage function. string clear_data = tex->get_clear_data(); @@ -10685,12 +10701,13 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, _glClearTexImage(gtc->_index, n - mipmap_bias, external_format, component_type, (void *)clear_data.data()); continue; - } else { - // Ask the Texture class to create the mipmap level in RAM. - // It'll fill it in with the correct clear color, which we - // can then upload. - ptimage = tex->make_ram_mipmap_image(n); } +#endif // OPENGLES + // Ask the Texture class to create the mipmap level in RAM. + // It'll fill it in with the correct clear color, which we + // can then upload. + ptimage = tex->make_ram_mipmap_image(n); + } else { // No clear color and no more images. break; @@ -10726,13 +10743,8 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, _data_transferred_pcollector.add_level(view_size); #endif switch (texture_target) { -#ifdef OPENGLES_2 - case GL_TEXTURE_3D_OES: -#endif -#ifndef OPENGLES - case GL_TEXTURE_3D: -#endif #ifndef OPENGLES_1 + case GL_TEXTURE_3D: if (_supports_3d_texture) { if (image_compression == Texture::CM_off) { _glTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth, @@ -10746,7 +10758,9 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, return false; } break; +#endif // OPENGLES_1 +#ifndef OPENGLES case GL_TEXTURE_1D: if (image_compression == Texture::CM_off) { glTexSubImage1D(page_target, n - mipmap_bias, 0, width, @@ -10756,7 +10770,8 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, external_format, view_size, image_ptr); } break; -#endif +#endif // OPENGLES + #ifndef OPENGLES case GL_TEXTURE_2D_ARRAY_EXT: if (_supports_2d_texture_array) { @@ -10772,7 +10787,8 @@ upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, return false; } break; -#endif +#endif // OPENGLES + default: if (image_compression == Texture::CM_off) { if (n==0) { @@ -11319,7 +11335,7 @@ do_extract_texture_data(CLP(TextureContext) *gtc) { type = Texture::T_unsigned_int_24_8; format = Texture::F_depth_stencil; break; -#ifndef OPENGLES_1 +#ifndef OPENGLES case GL_DEPTH32F_STENCIL8: type = Texture::T_float; format = Texture::F_depth_stencil; @@ -11483,26 +11499,34 @@ do_extract_texture_data(CLP(TextureContext) *gtc) { format = Texture::F_alpha; break; case GL_LUMINANCE: +#ifndef OPENGLES case GL_LUMINANCE16: case GL_LUMINANCE16F_ARB: +#endif case 1: format = Texture::F_luminance; break; case GL_LUMINANCE_ALPHA: +#ifndef OPENGLES case GL_LUMINANCE_ALPHA16F_ARB: +#endif case 2: format = Texture::F_luminance_alpha; break; #ifndef OPENGLES_1 case GL_SRGB: +#ifndef OPENGLES case GL_SRGB8: +#endif format = Texture::F_srgb; break; case GL_SRGB_ALPHA: case GL_SRGB8_ALPHA8: format = Texture::F_srgb_alpha; break; +#endif // OPENGLES_1 +#ifndef OPENGLES case GL_SLUMINANCE: case GL_SLUMINANCE8: format = Texture::F_sluminance; @@ -11511,7 +11535,7 @@ do_extract_texture_data(CLP(TextureContext) *gtc) { case GL_SLUMINANCE8_ALPHA8: format = Texture::F_sluminance_alpha; break; -#endif +#endif // OPENGLES #ifndef OPENGLES case GL_COMPRESSED_RGB: @@ -11561,7 +11585,7 @@ do_extract_texture_data(CLP(TextureContext) *gtc) { format = Texture::F_rgbm; compression = Texture::CM_dxt1; break; -#ifndef OPENGLES_1 +#ifndef OPENGLES case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: format = Texture::F_srgb; compression = Texture::CM_dxt1; @@ -11572,25 +11596,6 @@ do_extract_texture_data(CLP(TextureContext) *gtc) { break; #endif -#ifdef OPENGLES_2 - case GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT: - format = Texture::F_srgb; - compression = Texture::CM_pvr1_2bpp; - break; - case GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT: - format = Texture::F_srgb_alpha; - compression = Texture::CM_pvr1_2bpp; - break; - case GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT: - format = Texture::F_srgb; - compression = Texture::CM_pvr1_4bpp; - break; - case GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT: - format = Texture::F_srgb_alpha; - compression = Texture::CM_pvr1_4bpp; - break; -#endif // OPENGLES_2 - #ifdef OPENGLES case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: format = Texture::F_rgb; @@ -11963,6 +11968,7 @@ do_issue_stencil() { << "SRS_back_stencil_pass_z_pass_operation " << (int)stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_pass_operation) << "\n"; } +#ifndef OPENGLES if (_supports_two_sided_stencil) { //TODO: add support for OpenGL 2.0-style glStencilFuncSeparate. unsigned int back_compare; @@ -11989,6 +11995,7 @@ do_issue_stencil() { _glActiveStencilFaceEXT(GL_FRONT); } +#endif // OPENGLES unsigned int front_compare; front_compare = stencil->get_render_state(StencilAttrib::SRS_front_comparison_function); @@ -12018,9 +12025,11 @@ do_issue_stencil() { } } else { glDisable(GL_STENCIL_TEST); +#ifndef OPENGLES if (_supports_two_sided_stencil) { glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); } +#endif // OPENGLES } } @@ -12067,9 +12076,12 @@ do_issue_scissor() { if (_scissor_array.size() > 0) { // Scissoring is enabled on the display region. // Revert to the scissor state specified in the DisplayRegion. +#ifndef OPENGLES if (_supports_viewport_arrays) { _glScissorArrayv(0, _scissor_array.size(), _scissor_array[0].get_data()); - } else { + } else +#endif // OPENGLES + { const LVecBase4i sr = _scissor_array[0]; glScissor(sr[0], sr[1], sr[2], sr[3]); } diff --git a/panda/src/glstuff/glSamplerContext_src.cxx b/panda/src/glstuff/glSamplerContext_src.cxx index 4231baec59..13f4129071 100644 --- a/panda/src/glstuff/glSamplerContext_src.cxx +++ b/panda/src/glstuff/glSamplerContext_src.cxx @@ -14,6 +14,8 @@ #include "pnotify.h" +#ifndef OPENGLES + TypeHandle CLP(SamplerContext)::_type_handle; //////////////////////////////////////////////////////////////////// @@ -81,3 +83,5 @@ reset_data() { // re-load the sampler later. //glGenSamplers(1, &_index); } + +#endif // OPENGLES diff --git a/panda/src/glstuff/glSamplerContext_src.h b/panda/src/glstuff/glSamplerContext_src.h index f5f2d8a05b..12c2772987 100644 --- a/panda/src/glstuff/glSamplerContext_src.h +++ b/panda/src/glstuff/glSamplerContext_src.h @@ -12,6 +12,8 @@ // //////////////////////////////////////////////////////////////////// +#ifndef OPENGLES + #include "pandabase.h" #include "samplerContext.h" #include "deletedChain.h" @@ -56,3 +58,5 @@ public: private: static TypeHandle _type_handle; }; + +#endif // OPENGLES diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index e6a0d4551e..8126f4a2e4 100755 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -821,10 +821,12 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext param_type == GL_INT_VEC2 || param_type == GL_INT_VEC3 || param_type == GL_INT_VEC4 || - param_type == GL_UNSIGNED_INT || +#ifndef OPENGLES param_type == GL_UNSIGNED_INT_VEC2 || param_type == GL_UNSIGNED_INT_VEC3 || - param_type == GL_UNSIGNED_INT_VEC4); + param_type == GL_UNSIGNED_INT_VEC4 || +#endif + param_type == GL_UNSIGNED_INT ); if (noprefix.empty()) { // Arbitrarily named attribute. @@ -863,12 +865,16 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext // Get the number of bind points. switch (param_type) { case GL_FLOAT_MAT3: +#ifndef OPENGLES case GL_DOUBLE_MAT3: +#endif bind._elements = 3 * param_size; break; case GL_FLOAT_MAT4: +#ifndef OPENGLES case GL_DOUBLE_MAT4: +#endif bind._elements = 4 * param_size; break; diff --git a/panda/src/glstuff/glmisc_src.cxx b/panda/src/glstuff/glmisc_src.cxx index 9ea8411923..b4e1430ac1 100644 --- a/panda/src/glstuff/glmisc_src.cxx +++ b/panda/src/glstuff/glmisc_src.cxx @@ -283,7 +283,9 @@ void CLP(init_classes)() { CLP(ShaderContext)::init_type(); #endif CLP(TextureContext)::init_type(); +#ifndef OPENGLES CLP(SamplerContext)::init_type(); +#endif CLP(VertexBufferContext)::init_type(); CLP(GraphicsBuffer)::init_type(); From 7ed8cc98318cb25eec5b39eb9148854a291a811d Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 11 Feb 2015 21:54:34 +0100 Subject: [PATCH 03/32] Add p3d_Color uniform in GLSL shaders --- panda/src/glstuff/glShaderContext_src.cxx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index 8126f4a2e4..33b48f1298 100755 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -412,6 +412,20 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext s->_mat_spec.push_back(bind); continue; } + if (noprefix == "Color") { + Shader::ShaderMatSpec bind; + bind._id = arg_id; + bind._piece = Shader::SMP_row3; + bind._func = Shader::SMF_first; + bind._part[0] = Shader::SMO_attr_color; + bind._arg[0] = NULL; + bind._dep[0] = Shader::SSD_general | Shader::SSD_color; + bind._part[1] = Shader::SMO_identity; + bind._arg[1] = NULL; + bind._dep[1] = Shader::SSD_NONE; + s->_mat_spec.push_back(bind); + continue; + } if (noprefix == "ClipPlane") { for (int i = 0; i < param_size; ++i) { Shader::ShaderMatSpec bind; From d447ec3bc60cf923d572be2e1b0fee75838bc650 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 15 Feb 2015 14:19:47 +0100 Subject: [PATCH 04/32] If GL_RENDERER begins with "Gallium", disable GL_PRIMITIVE_RESTART_FIXED_INDEX --- panda/src/glstuff/glGraphicsStateGuardian_src.cxx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 8845d69f61..76087d4644 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -558,10 +558,13 @@ reset() { _glPrimitiveRestartIndex = NULL; if (gl_support_primitive_restart_index) { - if (is_at_least_gl_version(4, 3) || has_extension("GL_ARB_ES3_compatibility")) { + if ((is_at_least_gl_version(4, 3) || has_extension("GL_ARB_ES3_compatibility")) && + _gl_renderer.substr(0, 7) != "Gallium") { // As long as we enable this, OpenGL will always use the highest possible index // for a numeric type as strip cut index, which coincides with our convention. - // This saves us a call to glPrimitiveRestartIndex. + // This saves us a call to glPrimitiveRestartIndex + // ... of course, though, the Gallium driver bugs out here. See also: + // https://www.panda3d.org/forums/viewtopic.php?f=5&t=17512 glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); _supported_geom_rendering |= Geom::GR_strip_cut_index; From 0fda35d88c9fdef9fbb423b3288111dd82b93f97 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 16 Feb 2015 21:33:38 +0100 Subject: [PATCH 05/32] Commit patch by nikolm to support AmbientLight shader inputs in GLSL --- panda/src/display/graphicsStateGuardian.cxx | 65 ++++++++++++++------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 6dda4cb69a..1263339604 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -1407,22 +1407,29 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, static const CPT_InternalName IN_quadraticAttenuation("quadraticAttenuation"); if (attrib == IN_ambient) { -#ifndef NDEBUG Light *light = np.node()->as_light(); nassertr(light != (Light *)NULL, &LMatrix4::ident_mat()); -#endif - // Lights don't currently have an ambient color in Panda3D. - // We still have to support the attribute. - t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f)); + if (np.node()->is_of_type(AmbientLight::get_class_type())) { + LColor c = light->get_color(); + c.componentwise_mult(_light_color_scale); + t.set_row(3, c); + } else { + // Non-ambient lights don't currently have an ambient color in Panda3D. + t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f)); + } return &t; } else if (attrib == IN_diffuse) { Light *light = np.node()->as_light(); nassertr(light != (Light *)NULL, &LMatrix4::ones_mat()); - - LColor c = light->get_color(); - c.componentwise_mult(_light_color_scale); - t.set_row(3, c); + if (np.node()->is_of_type(AmbientLight::get_class_type())) { + // Ambient light has no diffuse color. + t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f)); + } else { + LColor c = light->get_color(); + c.componentwise_mult(_light_color_scale); + t.set_row(3, c); + } return &t; } else if (attrib == IN_specular) { @@ -1432,7 +1439,11 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, return &t; } else if (attrib == IN_position) { - if (np.node()->is_of_type(DirectionalLight::get_class_type())) { + if (np.node()->is_of_type(AmbientLight::get_class_type())) { + // Ambient light has no position. + t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); + return &t; + } else if (np.node()->is_of_type(DirectionalLight::get_class_type())) { DirectionalLight *light; DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat()); @@ -1458,7 +1469,11 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, } } else if (attrib == IN_halfVector) { - if (np.node()->is_of_type(DirectionalLight::get_class_type())) { + if (np.node()->is_of_type(AmbientLight::get_class_type())) { + // Ambient light has no half-vector. + t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); + return &t; + } else if (np.node()->is_of_type(DirectionalLight::get_class_type())) { DirectionalLight *light; DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat()); @@ -1490,19 +1505,25 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, } } else if (attrib == IN_spotDirection) { - LightLensNode *light; - DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat()); - Lens *lens = light->get_lens(); - nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat()); + if (np.node()->is_of_type(AmbientLight::get_class_type())) { + // Ambient light has no spot direction. + t.set_row(3, LVector3(0.0f, 0.0f, 0.0f)); + return &t; + } else { + LightLensNode *light; + DCAST_INTO_R(light, np.node(), &LMatrix4::ident_mat()); + Lens *lens = light->get_lens(); + nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat()); - CPT(TransformState) transform = - get_scene()->get_cs_world_transform()->compose( - np.get_transform(_scene_setup->get_scene_root().get_parent())); + CPT(TransformState) transform = + get_scene()->get_cs_world_transform()->compose( + np.get_transform(_scene_setup->get_scene_root().get_parent())); - const LMatrix4 &light_mat = transform->get_mat(); - LVector3 dir = lens->get_view_vector() * light_mat; - t.set_row(3, dir); - return &t; + const LMatrix4 &light_mat = transform->get_mat(); + LVector3 dir = lens->get_view_vector() * light_mat; + t.set_row(3, dir); + return &t; + } } else if (attrib == IN_spotCutoff) { if (np.node()->is_of_type(Spotlight::get_class_type())) { From b7ef0d3bc39d78e1794674c8db929b18d267d0fa Mon Sep 17 00:00:00 2001 From: enn0x Date: Fri, 20 Feb 2015 01:14:12 +0100 Subject: [PATCH 06/32] Exposed flag to disable collision between linked bodies. --- panda/src/bullet/bulletWorld.cxx | 9 +++++---- panda/src/bullet/bulletWorld.h | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/panda/src/bullet/bulletWorld.cxx b/panda/src/bullet/bulletWorld.cxx index 07a891aa4c..bee0b72f39 100644 --- a/panda/src/bullet/bulletWorld.cxx +++ b/panda/src/bullet/bulletWorld.cxx @@ -608,11 +608,12 @@ remove_vehicle(BulletVehicle *vehicle) { //////////////////////////////////////////////////////////////////// // Function: BulletWorld::attach_constraint // Access: Published -// Description: Deprecated! -// Please use BulletWorld::attach +// Description: Attaches a single constraint to a world. Collision +// checks between the linked objects will be disabled +// if the second parameter is set to TRUE. //////////////////////////////////////////////////////////////////// void BulletWorld:: -attach_constraint(BulletConstraint *constraint) { +attach_constraint(BulletConstraint *constraint, bool linked_collision) { nassertv(constraint); @@ -622,7 +623,7 @@ attach_constraint(BulletConstraint *constraint) { if (found == _constraints.end()) { _constraints.push_back(constraint); - _world->addConstraint(constraint->ptr()); + _world->addConstraint(constraint->ptr(), linked_collision); } else { bullet_cat.warning() << "constraint already attached" << endl; diff --git a/panda/src/bullet/bulletWorld.h b/panda/src/bullet/bulletWorld.h index 6a798cde7f..88fca5abd1 100644 --- a/panda/src/bullet/bulletWorld.h +++ b/panda/src/bullet/bulletWorld.h @@ -70,6 +70,8 @@ PUBLISHED: // Attach/Remove void attach(TypedObject *object); + void attach_constraint(BulletConstraint *constraint, bool linked_collision=false); + void remove(TypedObject *object); // Ghost object @@ -172,7 +174,6 @@ PUBLISHED: // Deprecated methods, will become private soon void attach_character(BulletBaseCharacterControllerNode *node); void remove_character(BulletBaseCharacterControllerNode *node); - void attach_constraint(BulletConstraint *constraint); void remove_constraint(BulletConstraint *constraint); public: From d320aced735d4b63bceeab8b845148ee713a9f1d Mon Sep 17 00:00:00 2001 From: enn0x Date: Fri, 20 Feb 2015 01:29:16 +0100 Subject: [PATCH 07/32] Fixed const-correctness for BulletAllHitRayResult. --- panda/src/bullet/bulletAllHitsRayResult.cxx | 2 +- panda/src/bullet/bulletAllHitsRayResult.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/panda/src/bullet/bulletAllHitsRayResult.cxx b/panda/src/bullet/bulletAllHitsRayResult.cxx index 953390820e..7d57feb767 100644 --- a/panda/src/bullet/bulletAllHitsRayResult.cxx +++ b/panda/src/bullet/bulletAllHitsRayResult.cxx @@ -156,7 +156,7 @@ get_hit_fraction() const { // Access: Published // Description: //////////////////////////////////////////////////////////////////// -PandaNode *BulletRayHit:: +const PandaNode *BulletRayHit:: get_node() const { return (_object) ? (PandaNode *)_object->getUserPointer() : NULL; diff --git a/panda/src/bullet/bulletAllHitsRayResult.h b/panda/src/bullet/bulletAllHitsRayResult.h index 6825e0ff68..26e04034af 100644 --- a/panda/src/bullet/bulletAllHitsRayResult.h +++ b/panda/src/bullet/bulletAllHitsRayResult.h @@ -33,7 +33,7 @@ struct EXPCL_PANDABULLET BulletRayHit { PUBLISHED: INLINE static BulletRayHit empty(); - PandaNode *get_node() const; + const PandaNode *get_node() const; LPoint3 get_hit_pos() const; LVector3 get_hit_normal() const; PN_stdfloat get_hit_fraction() const; From 2dd1b5e3b3113dd30336ebcc069588944dec580d Mon Sep 17 00:00:00 2001 From: deflected Date: Fri, 20 Feb 2015 11:58:28 +0200 Subject: [PATCH 08/32] dtool: Fixed building under FreeBSD There is missing define in dtoolutil which prevent building of dtool under FreeBSD. Signed-off-by: deflected --- dtool/src/dtoolutil/executionEnvironment.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtool/src/dtoolutil/executionEnvironment.cxx b/dtool/src/dtoolutil/executionEnvironment.cxx index 059bce8fcd..3f06a3427f 100644 --- a/dtool/src/dtoolutil/executionEnvironment.cxx +++ b/dtool/src/dtoolutil/executionEnvironment.cxx @@ -60,7 +60,7 @@ extern char **environ; #include #endif -#if defined(IS_LINUX) || defined(IS_OSX) +#if defined(IS_LINUX) || defined(IS_OSX) || defined(IS_FREEBSD) // For link_map and dlinfo. #include #include From d82f2c83cdf81b3cd45e1c61a335d439f11805be Mon Sep 17 00:00:00 2001 From: deflected Date: Fri, 20 Feb 2015 13:59:35 +0200 Subject: [PATCH 09/32] downloader: Correct lack of timezone - Use tm_gmtoff for GMT correction under FreeBSD Signed-off-by: deflected --- panda/src/downloader/httpDate.cxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/panda/src/downloader/httpDate.cxx b/panda/src/downloader/httpDate.cxx index fd9d01e8ed..ea143e0bfa 100644 --- a/panda/src/downloader/httpDate.cxx +++ b/panda/src/downloader/httpDate.cxx @@ -223,8 +223,14 @@ HTTPDate(const string &format) { if (_time != (time_t)-1) { // Unfortunately, mktime() assumes local time; convert this back // to GMT. +#ifdef IS_FREEBSD + time_t now = time(NULL); + struct tm *tp = localtime(&now); + _time -= tp->tm_gmtoff; +#else /* IS_FREEBSD */ extern long int timezone; _time -= timezone; +#endif /* IS_FREEBSD */ } #endif // __GNUC__ } From 3600abfe6db5ef79a149179fadfa750dcc4859e7 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 22 Feb 2015 13:51:46 +0100 Subject: [PATCH 10/32] Fix coercion of non-interned strings in Python 3 --- panda/src/gobj/internalName_ext.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/gobj/internalName_ext.cxx b/panda/src/gobj/internalName_ext.cxx index 5d15fd5e6d..dfdb8e8e36 100644 --- a/panda/src/gobj/internalName_ext.cxx +++ b/panda/src/gobj/internalName_ext.cxx @@ -36,7 +36,7 @@ make(PyUnicodeObject *str) { } string name(c_str, len); - return InternalName::make(c_str, len); + return InternalName::make(name); } InternalName::PyInternTable::const_iterator it; From 6263a591be0174543c866b389278107df5052bd5 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 22 Feb 2015 15:04:54 +0100 Subject: [PATCH 11/32] Fix matrix.almost_equal with custom threshold in Eigen build --- panda/src/linmath/lmatrix3_src.cxx | 2 +- panda/src/linmath/lmatrix4_src.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/panda/src/linmath/lmatrix3_src.cxx b/panda/src/linmath/lmatrix3_src.cxx index 6906aa503f..994056de79 100644 --- a/panda/src/linmath/lmatrix3_src.cxx +++ b/panda/src/linmath/lmatrix3_src.cxx @@ -353,7 +353,7 @@ bool FLOATNAME(LMatrix3):: almost_equal(const FLOATNAME(LMatrix3) &other, FLOATTYPE threshold) const { TAU_PROFILE("bool LMatrix3::almost_equal(const LMatrix3 &, FLOATTYPE)", " ", TAU_USER); #ifdef HAVE_EIGEN - return ((_m - other._m).cwiseAbs().maxCoeff() < NEARLY_ZERO(FLOATTYPE)); + return ((_m - other._m).cwiseAbs().maxCoeff() < threshold); #else return (IS_THRESHOLD_EQUAL((*this)(0, 0), other(0, 0), threshold) && IS_THRESHOLD_EQUAL((*this)(0, 1), other(0, 1), threshold) && diff --git a/panda/src/linmath/lmatrix4_src.cxx b/panda/src/linmath/lmatrix4_src.cxx index 4123fd17aa..75775f9217 100644 --- a/panda/src/linmath/lmatrix4_src.cxx +++ b/panda/src/linmath/lmatrix4_src.cxx @@ -296,7 +296,7 @@ bool FLOATNAME(LMatrix4):: almost_equal(const FLOATNAME(LMatrix4) &other, FLOATTYPE threshold) const { TAU_PROFILE("bool LMatrix4::almost_equal(const LMatrix4 &, FLOATTYPE)", " ", TAU_USER); #ifdef HAVE_EIGEN - return ((_m - other._m).cwiseAbs().maxCoeff() < NEARLY_ZERO(FLOATTYPE)); + return ((_m - other._m).cwiseAbs().maxCoeff() < threshold); #else return (IS_THRESHOLD_EQUAL((*this)(0, 0), other(0, 0), threshold) && IS_THRESHOLD_EQUAL((*this)(0, 1), other(0, 1), threshold) && From 9aafde057935b2f27356e1b30054b4bdf5f5cad4 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 24 Feb 2015 14:59:32 +0100 Subject: [PATCH 12/32] Add animation support to dae2egg --- pandatool/src/daeegg/daeCharacter.cxx | 328 +++++++++-- pandatool/src/daeegg/daeCharacter.h | 55 +- pandatool/src/daeegg/daeMaterials.cxx | 21 +- pandatool/src/daeegg/daeToEggConverter.cxx | 617 +++++++++++++-------- pandatool/src/daeegg/daeToEggConverter.h | 43 +- pandatool/src/daeprogs/daeToEgg.cxx | 8 + 6 files changed, 759 insertions(+), 313 deletions(-) diff --git a/pandatool/src/daeegg/daeCharacter.cxx b/pandatool/src/daeegg/daeCharacter.cxx index cb2633653a..d3c091d7bf 100644 --- a/pandatool/src/daeegg/daeCharacter.cxx +++ b/pandatool/src/daeegg/daeCharacter.cxx @@ -17,88 +17,316 @@ #include "fcollada_utils.h" #include "pt_EggVertex.h" #include "eggXfmSAnim.h" +#include "daeToEggConverter.h" +#include "daeMaterials.h" + +#include "eggExternalReference.h" #include "FCDocument/FCDocument.h" #include "FCDocument/FCDController.h" +#include "FCDocument/FCDGeometry.h" #include "FCDocument/FCDSceneNodeTools.h" +#include "FCDocument/FCDSceneNode.h" +#include "FCDocument/FCDTransform.h" +#include "FCDocument/FCDAnimated.h" +#include "FCDocument/FCDAnimationCurve.h" +#include "FCDocument/FCDAnimationKey.h" + TypeHandle DaeCharacter::_type_handle; //////////////////////////////////////////////////////////////////// // Function: DaeCharacter::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// DaeCharacter:: -DaeCharacter(const string name, const FCDControllerInstance* controller_instance) { - _controller_instance = (FCDControllerInstance*) controller_instance; - _name = name; - _frame_rate = 0; - _skin_controller = NULL; +DaeCharacter(EggGroup *node_group, const FCDControllerInstance *instance) : + _node_group(node_group), + _name(node_group->get_name()), + _instance(instance), + _skin_controller(NULL), + _skin_mesh(NULL) { + + _bind_shape_mat = LMatrix4d::ident_mat(); + // If it's a skin controller, add the controller joints. - FCDController* controller = (FCDController*) controller_instance->GetEntity(); - if (controller == NULL) return; + const FCDController *controller = (const FCDController *)instance->GetEntity(); + if (controller == NULL) { + return; + } + _skin_mesh = controller->GetBaseGeometry()->GetMesh(); + if (controller->IsSkin()) { _skin_controller = controller->GetSkinController(); - if (_skin_controller == NULL) return; - for (size_t j = 0; j < _skin_controller->GetJointCount(); ++j) { - _controller_joints[FROM_FSTRING(_skin_controller->GetJoint(j)->GetId())] = (FCDSkinControllerJoint*) _skin_controller->GetJoint(j); + _bind_shape_mat = DAEToEggConverter::convert_matrix(_skin_controller->GetBindShapeTransform()); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeCharacter::bind_joints +// Access: Public +// Description: Binds the joints to the character. This means +// changing them to the bind pose. It is necessary +// to call this before process_skin_geometry. +// +// Returns the root group. +//////////////////////////////////////////////////////////////////// +void DaeCharacter:: +bind_joints(JointMap &joint_map) { + _joints.clear(); + + size_t num_joints = _skin_controller->GetJointCount(); + _joints.reserve(num_joints); + + // Record the bind pose for each joint. + for (size_t j = 0; j < num_joints; ++j) { + const FCDSkinControllerJoint *skin_joint = _skin_controller->GetJoint(j); + string sid = FROM_FSTRING(skin_joint->GetId()); + LMatrix4d bind_pose; + bind_pose.invert_from(DAEToEggConverter::convert_matrix( + skin_joint->GetBindPoseInverse())); + + // Check that we already encountered this joint during traversal. + JointMap::iterator ji = joint_map.find(sid); + if (ji != joint_map.end()) { + Joint &joint = ji->second; + + if (joint._character != (DaeCharacter *)NULL) { + // In some cases, though, multiple controllers share the same joints. + // We can't support this without duplicating the joint structure, + // so we check if the bind poses are the same. + if (!joint._bind_pose.almost_equal(bind_pose, 0.0001)) { + // Ugh. What else could we do? + daeegg_cat.error() + << "Multiple controllers share joint with sid " << sid + << ", with different bind poses.\n"; + } + } else { + // Mark the joint as being controlled by this character. + joint._bind_pose = bind_pose; + joint._character = this; + } + + _joints.push_back(joint); + } else { + daeegg_cat.warning() + << "Unknown joint sid being referenced: '" << sid << "'\n"; + + // We still have to add a dummy joint or the index will be off. + _joints.push_back(Joint(NULL, NULL)); } } } //////////////////////////////////////////////////////////////////// -// Function: DaeCharacter::as_egg_bundle +// Function: DaeCharacter::adjust_joints // Access: Public -// Description: Returns the character as a element, -// suited for the animation table. +// Description: Traverses through the character hierarchy in order +// to bind the mesh to the character. This involves +// reorienting the joints to match the bind pose. +// +// It is important that this is called only once. //////////////////////////////////////////////////////////////////// -PT(EggTable) DaeCharacter:: -as_egg_bundle() { - PT(EggTable) bundle = new EggTable(_name); - bundle->set_table_type(EggTable::TT_bundle); - PT(EggTable) skeleton = new EggTable(""); - skeleton->set_table_type(EggTable::TT_table); - bundle->add_child(skeleton); - // Loop through the joint hierarchy -#if FCOLLADA_VERSION < 0x00030005 - FCDSceneNodeList roots = _controller_instance->FindSkeletonNodes(); -#else - FCDSceneNodeList roots; - _controller_instance->FindSkeletonNodes(roots); -#endif - for (FCDSceneNodeList::iterator it = roots.begin(); it != roots.end(); ++it) { - process_joint(skeleton, *it); +void DaeCharacter:: +adjust_joints(FCDSceneNode *node, const JointMap &joint_map, + const LMatrix4d &transform) { + + LMatrix4d this_transform = transform; + + if (node->IsJoint()) { + string sid = FROM_FSTRING(node->GetSubId()); + + JointMap::const_iterator ji = joint_map.find(sid); + if (ji != joint_map.end()) { + const Joint &joint = ji->second; + + // Panda needs the joints to be in bind pose. Not fun! We copy the joint + // transform to the default pose, though, so that Panda will restore the + // joint transformation after binding. + + if (joint._character == this) { + LMatrix4d bind_pose = joint._bind_pose * _bind_shape_mat * + invert(transform); + //LMatrix4d bind_pose = joint._bind_pose * _bind_shape_mat * + // joint._group->get_parent()->get_node_frame_inv(); + + this_transform = bind_pose * this_transform; + joint._group->set_default_pose(*joint._group); + joint._group->set_transform3d(bind_pose); + + /* + PT(EggGroup) sphere = new EggGroup; + sphere->add_uniform_scale(0.1); + sphere->set_group_type(EggGroup::GT_instance); + sphere->add_child(new EggExternalReference("", "jack.egg")); + joint._group->add_child(sphere); + */ + } + } + } else { + //this_transform = DAEToEggConverter::convert_matrix(node->ToMatrix()); + } + + // Loop through the children joints + for (size_t ch = 0; ch < node->GetChildrenCount(); ++ch) { + //if (node->GetChild(ch)->IsJoint()) { + adjust_joints(node->GetChild(ch), joint_map, this_transform); + //} } - return bundle; } //////////////////////////////////////////////////////////////////// -// Function: DaeCharacter::process_joint +// Function: DaeCharacter::influence_vertex +// Access: Public +// Description: Adds the influences for the given vertex. +//////////////////////////////////////////////////////////////////// +void DaeCharacter:: +influence_vertex(int index, EggVertex *vertex) { + const FCDSkinControllerVertex *influence = _skin_controller->GetVertexInfluence(index); + + for (size_t pa = 0; pa < influence->GetPairCount(); ++pa) { + const FCDJointWeightPair* jwpair = influence->GetPair(pa); + + if (jwpair->jointIndex >= 0 && jwpair->jointIndex < _joints.size()) { + EggGroup *joint = _joints[jwpair->jointIndex]._group.p(); + if (joint != NULL) { + joint->ref_vertex(vertex, jwpair->weight); + } + } else { + daeegg_cat.error() + << "Invalid joint index: " << jwpair->jointIndex << "\n"; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeCharacter::collect_keys +// Access: Public +// Description: Collects all animation keys of animations applied +// to this character. +//////////////////////////////////////////////////////////////////// +void DaeCharacter:: +collect_keys(pset &keys) { +#if FCOLLADA_VERSION < 0x00030005 + FCDSceneNodeList roots = _instance->FindSkeletonNodes(); +#else + FCDSceneNodeList roots; + _instance->FindSkeletonNodes(roots); +#endif + + for (FCDSceneNodeList::iterator it = roots.begin(); it != roots.end(); ++it) { + r_collect_keys(*it, keys); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeCharacter::r_collect_keys +// Access: Public +// Description: Collects all animation keys found for the given +// node tree. +//////////////////////////////////////////////////////////////////// +void DaeCharacter:: +r_collect_keys(FCDSceneNode* node, pset &keys) { + FCDAnimatedList animateds; + + // Collect all the animation curves + for (size_t t = 0; t < node->GetTransformCount(); ++t) { + FCDTransform *transform = node->GetTransform(t); + FCDAnimated *animated = transform->GetAnimated(); + + if (animated != NULL) { + const FCDAnimationCurveListList &all_curves = animated->GetCurves(); + + for (size_t ci = 0; ci < all_curves.size(); ++ci) { + const FCDAnimationCurveTrackList &curves = all_curves[ci]; + if (curves.empty()) { + continue; + } + + size_t num_keys = curves.front()->GetKeyCount(); + const FCDAnimationKey **curve_keys = curves.front()->GetKeys(); + + for (size_t c = 0; c < num_keys; ++c) { + keys.insert(curve_keys[c]->input); + } + } + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DaeCharacter::build_table // Access: Public // Description: Processes a joint node and its transforms. //////////////////////////////////////////////////////////////////// void DaeCharacter:: -process_joint(PT(EggTable) parent, FCDSceneNode* node) { +build_table(EggTable *parent, FCDSceneNode* node, const pset &keys) { nassertv(node != NULL); - string node_id = FROM_FSTRING(node->GetDaeId()); - PT(EggTable) joint = new EggTable(node_id); - joint->set_table_type(EggTable::TT_table); - parent->add_child(joint); - PT(EggXfmSAnim) xform = new EggXfmSAnim("xform"); - joint->add_child(xform); - xform->set_fps(_frame_rate); - // Generate the sampled animation and loop through the matrices - FCDSceneNodeTools::GenerateSampledAnimation(node); - FMMatrix44List matrices = FCDSceneNodeTools::GetSampledAnimationMatrices(); - for (FMMatrix44List::const_iterator it = matrices.begin(); it != matrices.end(); ++it) { - LMatrix4d matr = DAEToEggConverter::convert_matrix(*it); - assert(xform->add_data(matr)); + + if (!node->IsJoint()) { + for (size_t ch = 0; ch < node->GetChildrenCount(); ++ch) { + build_table(parent, node->GetChild(ch), keys); + } + return; } - // Loop through the children joints - for (size_t ch = 0; ch < node->GetChildrenCount(); ++ch) { - if (node->GetChild(ch)->IsJoint()) { - process_joint(joint, node->GetChild(ch)); + + string node_id = FROM_FSTRING(node->GetDaeId()); + PT(EggTable) table = new EggTable(node_id); + table->set_table_type(EggTable::TT_table); + parent->add_child(table); + + PT(EggXfmSAnim) xform = new EggXfmSAnim("xform"); + table->add_child(xform); + + // Generate the sampled animation and loop through the matrices + FCDAnimatedList animateds; + + // Collect all the animation curves + for (size_t t = 0; t < node->GetTransformCount(); ++t) { + FCDTransform *transform = node->GetTransform(t); + FCDAnimated *animated = transform->GetAnimated(); + if (animated != (FCDAnimated *)NULL) { + if (animated->HasCurve()) { + animateds.push_back(animated); + } } } + + // Sample the scene node transform + float last_key; + float timing_total = 0; + pset::const_iterator ki; + for (ki = keys.begin(); ki != keys.end(); ++ki) { + for (FCDAnimatedList::iterator it = animateds.begin(); it != animateds.end(); ++it) { + // Sample each animated, which changes the transform values directly + (*it)->Evaluate(*ki); + } + + if (ki != keys.begin()) { + timing_total += (*ki - last_key); + } + last_key = *ki; + + // Retrieve the new transform matrix for the COLLADA scene node + FMMatrix44 fmat = node->ToMatrix(); + + // Work around issue in buggy exporters (like ColladaMax) + if (IS_NEARLY_ZERO(fmat[3][3])) { + fmat[3][3] = 1; + } + + xform->add_data(DAEToEggConverter::convert_matrix(fmat)); + } + + // Quantize the FPS, otherwise Panda complains about FPS mismatches. + float fps = round(((keys.size() - 1) / timing_total) * 100) * 0.01f; + xform->set_fps(fps); + + // Loop through the children joints + for (size_t ch = 0; ch < node->GetChildrenCount(); ++ch) { + //if (node->GetChild(ch)->IsJoint()) { + build_table(table, node->GetChild(ch), keys); + //} + } } diff --git a/pandatool/src/daeegg/daeCharacter.h b/pandatool/src/daeegg/daeCharacter.h index e7a85cbedf..cd656eae06 100644 --- a/pandatool/src/daeegg/daeCharacter.h +++ b/pandatool/src/daeegg/daeCharacter.h @@ -12,20 +12,22 @@ // //////////////////////////////////////////////////////////////////// +#ifndef DAECHARACTER_H +#define DAECHARACTER_H + #include "pandatoolbase.h" #include "typedReferenceCount.h" #include "typeHandle.h" #include "eggTable.h" -#include "daeToEggConverter.h" #include "pre_fcollada_include.h" #include "FCollada.h" #include "FCDocument/FCDSceneNode.h" #include "FCDocument/FCDControllerInstance.h" #include "FCDocument/FCDSkinController.h" +#include "FCDocument/FCDGeometryMesh.h" -#ifndef DAECHARACTER_H -#define DAECHARACTER_H +class DAEToEggConverter; //////////////////////////////////////////////////////////////////// // Class : DaeCharacter @@ -33,17 +35,46 @@ //////////////////////////////////////////////////////////////////// class DaeCharacter : public TypedReferenceCount { public: - DaeCharacter(const string name, const FCDControllerInstance* controller_instance); - PT(EggTable) as_egg_bundle(); - void process_joint(PT(EggTable) parent, FCDSceneNode* node); - + DaeCharacter(EggGroup *node_group, const FCDControllerInstance* controller_instance); + + struct Joint { + INLINE Joint(EggGroup *group, const FCDSceneNode *scene_node) : + _group(group), + _scene_node(scene_node), + _character(NULL), + _bind_pose(LMatrix4d::ident_mat()) {} + + LMatrix4d _bind_pose; + const PT(EggGroup) _group; + const FCDSceneNode *_scene_node; + DaeCharacter *_character; + }; + typedef pvector Joints; + typedef pmap JointMap; + + void bind_joints(JointMap &joint_map); + void adjust_joints(FCDSceneNode *node, const JointMap &joint_map, + const LMatrix4d &transform = LMatrix4d::ident_mat()); + + void influence_vertex(int index, EggVertex *vertex); + + void collect_keys(pset &keys); + void r_collect_keys(FCDSceneNode *node, pset &keys); + + void build_table(EggTable *parent, FCDSceneNode* node, const pset &keys); + +public: + PT(EggGroup) _node_group; + const FCDGeometryMesh *_skin_mesh; + const FCDControllerInstance *_instance; + LMatrix4d _bind_shape_mat; + private: - int _frame_rate; string _name; - FCDControllerInstance* _controller_instance; - FCDSkinController* _skin_controller; - pmap _controller_joints; - + const FCDSkinController *_skin_controller; + Joints _joints; + JointMap _bound_joints; + public: virtual TypeHandle get_type() const { return get_class_type(); diff --git a/pandatool/src/daeegg/daeMaterials.cxx b/pandatool/src/daeegg/daeMaterials.cxx index 4790c3bfc2..9d234489ab 100755 --- a/pandatool/src/daeegg/daeMaterials.cxx +++ b/pandatool/src/daeegg/daeMaterials.cxx @@ -35,7 +35,7 @@ TypeHandle DaeMaterials::_type_handle; //////////////////////////////////////////////////////////////////// // Function: DaeMaterials::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// DaeMaterials:: DaeMaterials(const FCDGeometryInstance* geometry_instance) { @@ -58,7 +58,7 @@ void DaeMaterials::add_material_instance(const FCDMaterialInstance* instance) { return; } _materials[semantic] = new DaeMaterial(); - + // Load in the uvsets for (size_t vib = 0; vib < instance->GetVertexInputBindingCount(); ++vib) { const FCDMaterialInstanceBindVertexInput* mivib = instance->GetVertexInputBinding(vib); @@ -74,7 +74,7 @@ void DaeMaterials::add_material_instance(const FCDMaterialInstance* instance) { #endif _materials[semantic]->_uvsets.push_back(bvi); } - + // Handle the material stuff daeegg_cat.spam() << "Trying to process material with semantic " << semantic << endl; PT_EggMaterial egg_material = new EggMaterial(semantic); @@ -204,12 +204,13 @@ process_extra(const string semantic, const FCDExtra* extra) { for (size_t et = 0; et < etype->GetTechniqueCount(); ++et) { const FCDENode* enode = ((const FCDENode*)(etype->GetTechnique(et)))->FindChildNode("double_sided"); if (enode != NULL) { - if (trim(enode->GetContent()) == "1") { + string content = trim(enode->GetContent()); + if (content == "1" || content == "true") { _materials[semantic]->_double_sided = true; - } else if (trim(enode->GetContent()) == "0") { + } else if (content == "0" || content == "false") { _materials[semantic]->_double_sided = false; } else { - daeegg_cat.warning() << "Expected tag to be either 1 or 0, found '" << enode->GetContent() << "' instead" << endl; + daeegg_cat.warning() << "Expected tag to be either 1 or 0, found '" << content << "' instead" << endl; } } } @@ -391,7 +392,7 @@ convert_blend(FCDEffectStandard::TransparencyMode mode, const LColor &transparen blend->_color = LColor::zero(); blend->_operand_a = EggGroup::BO_unspecified; blend->_operand_b = EggGroup::BO_unspecified; - + // First fill in the color value. if (mode == FCDEffectStandard::A_ONE) {// || mode == FCDEffectStandard::A_ZERO) { double value = transparent[3] * transparency; @@ -404,7 +405,7 @@ convert_blend(FCDEffectStandard::TransparencyMode mode, const LColor &transparen blend->_enabled = false; return blend; } - + // Now figure out the operands. if (mode == FCDEffectStandard::RGB_ZERO) {// || mode == FCDEffectStandard::A_ZERO) { blend->_operand_a = EggGroup::BO_one_minus_constant_color; @@ -417,7 +418,7 @@ convert_blend(FCDEffectStandard::TransparencyMode mode, const LColor &transparen blend->_enabled = false; return blend; } - + // See if we can optimize out the color. if (blend->_operand_a == EggGroup::BO_constant_color) { if (blend->_color == LColor::zero()) { @@ -447,7 +448,7 @@ convert_blend(FCDEffectStandard::TransparencyMode mode, const LColor &transparen blend->_operand_b = EggGroup::BO_zero; } } - + // See if we can entirely disable the blend. if (blend->_operand_a == EggGroup::BO_one && blend->_operand_b == EggGroup::BO_zero) { blend->_enabled = false; diff --git a/pandatool/src/daeegg/daeToEggConverter.cxx b/pandatool/src/daeegg/daeToEggConverter.cxx index 320255e63b..8ff46b401b 100755 --- a/pandatool/src/daeegg/daeToEggConverter.cxx +++ b/pandatool/src/daeegg/daeToEggConverter.cxx @@ -56,9 +56,10 @@ //////////////////////////////////////////////////////////////////// DAEToEggConverter:: DAEToEggConverter() { + _unit_name = "meter"; + _unit_meters = 1.0; _document = NULL; _table = NULL; - _frame_rate = -1; _error_handler = NULL; _invert_transparency = false; } @@ -131,18 +132,15 @@ convert_file(const Filename &filename) { // Reset stuff clear_error(); _joints.clear(); - _vertex_pools.clear(); - _skeletons.clear(); - _frame_rate = -1; if (_error_handler == NULL) { _error_handler = new FUErrorSimpleHandler; } - + // The default coordinate system is Y-up if (_egg_data->get_coordinate_system() == CS_default) { _egg_data->set_coordinate_system(CS_yup_right); } - + // Read the file FCollada::Initialize(); _document = FCollada::LoadDocument(filename.to_os_specific().c_str()); @@ -155,201 +153,375 @@ convert_file(const Filename &filename) { if (_document->GetAsset() != NULL) { FCDocumentTools::StandardizeUpAxisAndLength(_document); } - - _table = new EggTable(); - _table->set_table_type(EggTable::TT_table); - // Process the stuff + + // Process the scene process_asset(); - preprocess(); + PT(EggGroup) scene_group; + string model_name = _character_name; + FCDSceneNode* visual_scene = _document->GetVisualSceneInstance(); if (visual_scene != NULL) { - // First check for an tag - const FCDExtra* extra = visual_scene->GetExtra(); - //FIXME: eek this looks horrid - if (extra != NULL) { - const FCDEType* etype = extra->GetDefaultType(); - if (etype != NULL) { - const FCDENode* enode = (const FCDENode*) etype->FindTechnique("MAX3D"); - if (enode != NULL) { - enode = enode->FindChildNode("frame_rate"); - if (enode != NULL && !string_to_int(enode->GetContent(), _frame_rate)) { - daeegg_cat.warning() << "Invalid integer in tag: '" << enode->GetContent() << "'" << endl; - } } } } - // Now loop through the children + if (model_name.empty()) { + // By lack of anything better... + model_name = FROM_FSTRING(visual_scene->GetName()); + } + scene_group = new EggGroup(model_name); + _egg_data->add_child(scene_group); + for (size_t ch = 0; ch < visual_scene->GetChildrenCount(); ++ch) { - process_node(DCAST(EggGroupNode, _egg_data), visual_scene->GetChild(ch)); + process_node(scene_group, visual_scene->GetChild(ch)); + } + } else { + daeegg_cat.warning() + << "No visual scene instance found in COLLADA document.\n"; + } + + // Now process the characters. This depends on information from collected + // joints, which is why it's done in a second step. + if (get_animation_convert() != AC_none) { + Characters::iterator it; + DaeCharacter *character; + for (it = _characters.begin(); it != _characters.end(); ++it) { + character = *it; + if (get_animation_convert() != AC_chan) { + character->bind_joints(_joints); + + const FCDGeometryMesh *mesh = character->_skin_mesh; + + if (mesh != NULL) { + PT(DaeMaterials) materials = new DaeMaterials(character->_instance); + daeegg_cat.spam() << "Processing mesh for controller\n"; + process_mesh(character->_node_group, mesh, materials, character); + } + } + } + + // Put the joints in bind pose. + for (size_t ch = 0; ch < visual_scene->GetChildrenCount(); ++ch) { + character->adjust_joints(visual_scene->GetChild(ch), _joints, LMatrix4d::ident_mat()); + } + + if (scene_group != NULL) { + // Mark the scene as character. + if (get_animation_convert() == AC_chan) { + _egg_data->remove_child(scene_group); + } else { + scene_group->set_dart_type(EggGroup::DT_default); + } + } + + if (get_animation_convert() != AC_model) { + _table = new EggTable(); + _table->set_table_type(EggTable::TT_table); + _egg_data->add_child(_table); + + PT(EggTable) bundle = new EggTable(model_name); + bundle->set_table_type(EggTable::TT_bundle); + _table->add_child(bundle); + + PT(EggTable) skeleton = new EggTable(""); + skeleton->set_table_type(EggTable::TT_table); + bundle->add_child(skeleton); + + pset keys; + + Characters::iterator it; + DaeCharacter *character; + for (it = _characters.begin(); it != _characters.end(); ++it) { + DaeCharacter *character = *it; + + // Collect key frame timings. + if (get_animation_convert() == AC_both || + get_animation_convert() == AC_chan) { + character->collect_keys(keys); + } + } + + if (_frame_inc != 0.0) { + // A frame increment was given, this means that we have to sample the + // animation. + float start, end; + if (_end_frame != _start_frame) { + start = _start_frame; + end = _end_frame; + } else { + // No range was given. Infer the frame range from the keys. + start = *keys.begin(); + end = *keys.rbegin(); + } + keys.clear(); + + for (float t = start; t <= end; t += _frame_inc) { + keys.insert(t); + } + } else { + // No sampling parameters given; not necessarily a failure, since the + // animation may already be sampled. We use the key frames as animation + // frames. + if (_end_frame != 0.0) { + // An end frame was given, chop off all keys after that. + float end = _end_frame; + pset::iterator ki; + for (ki = keys.begin(); ki != keys.end(); ++ki) { + if (*ki > end && !IS_THRESHOLD_EQUAL(*ki, end, 0.001)) { + keys.erase(ki, keys.end()); + break; + } + } + } + if (_start_frame != 0.0) { + // A start frame was given, chop off all keys before that. + float start = _start_frame; + pset::iterator ki; + for (ki = keys.begin(); ki != keys.end(); ++ki) { + if (*ki > start && !IS_THRESHOLD_EQUAL(*ki, start, 0.001)) { + keys.erase(keys.begin(), ki); + break; + } + } + } + + // Check that this does indeed look like a sampled animation; if not, + // issue an appropriate warning. + pset::const_iterator ki = keys.begin(); + if (ki != keys.end()) { + float last = *ki; + float diff = 0; + + for (++ki; ki != keys.end(); ++ki) { + if (diff != 0 && !IS_THRESHOLD_EQUAL((*ki - last), diff, 0.001)) { + daeegg_cat.error() + << "This does not appear to be a sampled animation.\n" + << "Specify the -sf, -ef and -if options to indicate how the " + << "animations should be sampled.\n"; + break; + } + diff = (*ki - last); + last = *ki; + } + } + } + + // It doesn't really matter which character we grab for this as + // it'll iterate over the whole graph right now anyway. + for (size_t ch = 0; ch < visual_scene->GetChildrenCount(); ++ch) { + character->build_table(skeleton, visual_scene->GetChild(ch), keys); + } } } - SAFE_DELETE(visual_scene); - - _egg_data->add_child(_table); - + // Clean up and return + SAFE_DELETE(visual_scene); SAFE_DELETE(_document); FCollada::Release(); return true; } -void DAEToEggConverter::process_asset() { - if (_document->GetAsset() == NULL) return; +//////////////////////////////////////////////////////////////////// +// Function: DAEToEggConverter::get_input_units +// Access: Public, Virtual +// Description: This may be called after convert_file() has been +// called and returned true, indicating a successful +// conversion. It will return the distance units +// represented by the converted egg file, if known, or +// DU_invalid if not known. +//////////////////////////////////////////////////////////////////// +DistanceUnit DAEToEggConverter:: +get_input_units() { + if (IS_NEARLY_EQUAL(_unit_meters, 0.001)) { + return DU_millimeters; + } + if (IS_NEARLY_EQUAL(_unit_meters, 0.01)) { + return DU_centimeters; + } + if (IS_NEARLY_EQUAL(_unit_meters, 1.0)) { + return DU_meters; + } + if (IS_NEARLY_EQUAL(_unit_meters, 1000.0)) { + return DU_kilometers; + } + if (IS_NEARLY_EQUAL(_unit_meters, 3.0 * 12.0 * 0.0254)) { + return DU_yards; + } + if (IS_NEARLY_EQUAL(_unit_meters, 12.0 * 0.0254)) { + return DU_feet; + } + if (IS_NEARLY_EQUAL(_unit_meters, 0.0254)) { + return DU_inches; + } + if (IS_NEARLY_EQUAL(_unit_meters, 1852.0)) { + return DU_nautical_miles; + } + if (IS_NEARLY_EQUAL(_unit_meters, 5280.0 * 12.0 * 0.0254)) { + return DU_statute_miles; + } + + // Whatever. + return DU_invalid; +} + +void DAEToEggConverter:: +process_asset() { + const FCDAsset *asset = _document->GetAsset(); + if (_document->GetAsset() == NULL) { + return; + } + + _unit_name = FROM_FSTRING(asset->GetUnitName()); + _unit_meters = asset->GetUnitConversionFactor(); + // Read out the coordinate system - FMVector3 up_axis (_document->GetAsset()->GetUpAxis()); + FMVector3 up_axis = asset->GetUpAxis(); + if (up_axis == FMVector3(0, 1, 0)) { _egg_data->set_coordinate_system(CS_yup_right); + } else if (up_axis == FMVector3(0, 0, 1)) { _egg_data->set_coordinate_system(CS_zup_right); + } else { _egg_data->set_coordinate_system(CS_invalid); daeegg_cat.warning() << "Unrecognized coordinate system!\n"; } } -// This function lists all the joints and referenced skeletons -void DAEToEggConverter::preprocess(const FCDSceneNode* node) { - // If the node is NULL, take the visual scene instance. - if (node == NULL) { - assert(_document != NULL); - _skeletons.clear(); - _joints.clear(); - node = _document->GetVisualSceneInstance(); - } - if (node == NULL) return; - if (node->IsJoint()) { - _joints[FROM_FSTRING(node->GetDaeId())] = NULL; - } - // Loop through the instances first. - for (size_t in = 0; in < node->GetInstanceCount(); ++in) { - if (node->GetInstance(in)->GetType() == FCDEntityInstance::CONTROLLER) { - // Loop through the skeleton roots now. -#if FCOLLADA_VERSION < 0x00030005 - FCDSceneNodeList roots = ((FCDControllerInstance*) node->GetInstance(in))->FindSkeletonNodes(); -#else - FCDSceneNodeList roots; - ((FCDControllerInstance*) node->GetInstance(in))->FindSkeletonNodes(roots); -#endif - for (FCDSceneNodeList::iterator it = roots.begin(); it != roots.end(); ++it) { - daeegg_cat.spam() << "Found referenced skeleton root " << FROM_FSTRING((*it)->GetDaeId()) << endl; - _skeletons.push_back(FROM_FSTRING((*it)->GetDaeId())); - } - } - } - // Now loop through the children and recurse. - for (size_t ch = 0; ch < node->GetChildrenCount(); ++ch) { - preprocess(node->GetChild(ch)); - } -} - // Process the node. If forced is true, it will even process it if its known to be a skeleton root. -void DAEToEggConverter::process_node(PT(EggGroupNode) parent, const FCDSceneNode* node, bool forced) { +void DAEToEggConverter:: +process_node(EggGroupNode *parent, const FCDSceneNode* node, bool forced) { nassertv(node != NULL); string node_id = FROM_FSTRING(node->GetDaeId()); daeegg_cat.spam() << "Processing node with ID '" << node_id << "'" << endl; - // Important! If it's known to be a skeleton root, ignore it for now, unless we're processing forced. - if (!forced && count(_skeletons.begin(), _skeletons.end(), node_id) > 0) { - daeegg_cat.spam() << "Ignoring skeleton root node with ID '" << node_id << "', we'll process it later" << endl; - return; - } + // Create an egg group for this node - PT(EggGroup) node_group = new EggGroup(FROM_FSTRING(node->GetName())); + PT(EggGroup) node_group = new EggGroup(FROM_FSTRING(node->GetDaeId())); process_extra(node_group, node->GetExtra()); parent->add_child(node_group); + // Check if its a joint if (node->IsJoint()) { + string sid = FROM_FSTRING(node->GetSubId()); node_group->set_group_type(EggGroup::GT_joint); - _joints[node_id] = node_group; + + if (!_joints.insert(DaeCharacter::JointMap::value_type(sid, + DaeCharacter::Joint(node_group, node))).second) { + daeegg_cat.error() + << "Joint with sid " << sid << " occurs more than once!\n"; + } } - // Loop through the transforms and apply them - for (size_t tr = 0; tr < node->GetTransformCount(); ++tr) { - apply_transform(node_group, node->GetTransform(tr)); + + // Loop through the transforms and apply them (in reverse order) + for (size_t tr = node->GetTransformCount(); tr > 0; --tr) { + apply_transform(node_group, node->GetTransform(tr - 1)); } + //node_group->set_transform3d(convert_matrix(node->ToMatrix())); + // Loop through the instances and process them for (size_t in = 0; in < node->GetInstanceCount(); ++in) { process_instance(node_group, node->GetInstance(in)); } + // Loop through the children and recursively process them for (size_t ch = 0; ch < node->GetChildrenCount(); ++ch) { process_node(DCAST(EggGroupNode, node_group), node->GetChild(ch)); } + // Loop through any possible scene node instances and process those, too. for (size_t in = 0; in < node->GetInstanceCount(); ++in) { - if (node->GetInstance(in)->GetEntity() && node->GetInstance(in)->GetEntity()->GetType() == FCDEntity::SCENE_NODE) { - process_node(DCAST(EggGroupNode, node_group), (const FCDSceneNode*) node->GetInstance(in)->GetEntity()); + const FCDEntity *entity = node->GetInstance(in)->GetEntity(); + if (entity && entity->GetType() == FCDEntity::SCENE_NODE) { + process_node(node_group, (const FCDSceneNode*) entity); } } } -void DAEToEggConverter::process_instance(PT(EggGroup) parent, const FCDEntityInstance* instance) { +void DAEToEggConverter:: +process_instance(EggGroup *parent, const FCDEntityInstance* instance) { nassertv(instance != NULL); nassertv(instance->GetEntity() != NULL); // Check what kind of instance this is switch (instance->GetType()) { - case FCDEntityInstance::GEOMETRY: { - const FCDGeometry* geometry = (const FCDGeometry*) instance->GetEntity(); - assert(geometry != NULL); - if (geometry->IsMesh()) { - // Now, handle the mesh. - process_mesh(parent, geometry->GetMesh(), new DaeMaterials((const FCDGeometryInstance*) instance)); + case FCDEntityInstance::GEOMETRY: + { + if (get_animation_convert() != AC_chan) { + const FCDGeometry* geometry = (const FCDGeometry*) instance->GetEntity(); + assert(geometry != NULL); + if (geometry->IsMesh()) { + // Now, handle the mesh. + process_mesh(parent, geometry->GetMesh(), new DaeMaterials((const FCDGeometryInstance*) instance)); + } + if (geometry->IsSpline()) { + process_spline(parent, FROM_FSTRING(geometry->GetName()), const_cast (geometry->GetSpline())); + } } - if (geometry->IsSpline()) { - process_spline(parent, FROM_FSTRING(geometry->GetName()), const_cast (geometry->GetSpline())); - } - break; } - case FCDEntityInstance::CONTROLLER: { - // Add the dart tag and process the controller instance - parent->set_dart_type(EggGroup::DT_default); - process_controller(parent, (const FCDControllerInstance*) instance); - break; } - case FCDEntityInstance::MATERIAL: - // We don't process this directly, handled per-geometry instead. - break; - case FCDEntityInstance::SIMPLE: { - // Grab the entity and check it's type. + } + break; + + case FCDEntityInstance::CONTROLLER: + // Add the dart tag and process the controller instance + //parent->set_dart_type(EggGroup::DT_default); + process_controller(parent, (const FCDControllerInstance*) instance); + break; + + case FCDEntityInstance::MATERIAL: + // We don't process this directly, handled per-geometry instead. + break; + + case FCDEntityInstance::SIMPLE: + { + // Grab the entity and check its type. const FCDEntity* entity = instance->GetEntity(); if (entity->GetType() != FCDEntity::SCENE_NODE) { daeegg_cat.warning() << "Unsupported entity type found" << endl; } - break; } - default: - daeegg_cat.warning() << "Unsupported instance type found" << endl; + } + break; + + default: + daeegg_cat.warning() << "Unsupported instance type found" << endl; } } // Processes the given mesh. -void DAEToEggConverter::process_mesh(PT(EggGroup) parent, const FCDGeometryMesh* mesh, PT(DaeMaterials) materials) { +void DAEToEggConverter:: +process_mesh(EggGroup *parent, const FCDGeometryMesh* mesh, + DaeMaterials *materials, DaeCharacter *character) { + nassertv(mesh != NULL); daeegg_cat.debug() << "Processing mesh with id " << FROM_FSTRING(mesh->GetDaeId()) << endl; - + // Create the egg stuff to hold this mesh PT(EggGroup) mesh_group = new EggGroup(FROM_FSTRING(mesh->GetDaeId())); parent->add_child(mesh_group); PT(EggVertexPool) mesh_pool = new EggVertexPool(FROM_FSTRING(mesh->GetDaeId())); mesh_group->add_child(mesh_pool); - _vertex_pools[FROM_FSTRING(mesh->GetDaeId())] = mesh_pool; - + // First retrieve the vertex source if (mesh->GetSourceCount() == 0) { daeegg_cat.debug() << "Mesh with id " << FROM_FSTRING(mesh->GetDaeId()) << " has no sources" << endl; return; } - const FCDGeometrySource* vsource = mesh->FindSourceByType(FUDaeGeometryInput::POSITION); + const FCDGeometrySource* vsource = mesh->FindSourceByType(FUDaeGeometryInput::POSITION); if (vsource == NULL) { daeegg_cat.debug() << "Mesh with id " << FROM_FSTRING(mesh->GetDaeId()) << " has no source for POSITION data" << endl; return; } - + // Loop through the polygon groups and add them daeegg_cat.spam() << "Mesh with id " << FROM_FSTRING(mesh->GetDaeId()) << " has " << mesh->GetPolygonsCount() << " polygon groups" << endl; if (mesh->GetPolygonsCount() == 0) return; - + // This is an array of pointers, I know. But since they are refcounted, I don't have a better idea. PT(EggGroup) *primitive_holders = new PT(EggGroup) [mesh->GetPolygonsCount()]; for (size_t gr = 0; gr < mesh->GetPolygonsCount(); ++gr) { const FCDGeometryPolygons* polygons = mesh->GetPolygons(gr); + string material_semantic = FROM_FSTRING(polygons->GetMaterialSemantic()); + // Stores which group holds the primitives. PT(EggGroup) primitiveholder; // If we have materials, make a group for each material. Then, apply the material's per-group stuff. if (materials != NULL && (!polygons->GetMaterialSemantic().empty()) && mesh->GetPolygonsCount() > 1) { - primitiveholder = new EggGroup(FROM_FSTRING(mesh->GetDaeId()) + "." + FROM_FSTRING(polygons->GetMaterialSemantic())); + //primitiveholder = new EggGroup(FROM_FSTRING(mesh->GetDaeId()) + "." + material_semantic); + primitiveholder = new EggGroup; mesh_group->add_child(primitiveholder); } else { primitiveholder = mesh_group; @@ -357,7 +529,7 @@ void DAEToEggConverter::process_mesh(PT(EggGroup) parent, const FCDGeometryMesh* primitive_holders[gr] = primitiveholder; // Apply the per-group data of the materials, if we have it. if (materials != NULL) { - materials->apply_to_group(FROM_FSTRING(polygons->GetMaterialSemantic()), primitiveholder, _invert_transparency); + materials->apply_to_group(material_semantic, primitiveholder, _invert_transparency); } // Find the position sources const FCDGeometryPolygonsInput* pinput = polygons->FindInput(FUDaeGeometryInput::POSITION); @@ -389,26 +561,47 @@ void DAEToEggConverter::process_mesh(PT(EggGroup) parent, const FCDGeometryMesh* const uint32* tindices; if (tinput != NULL) tindices = tinput->GetIndices(); // Get a name for potential coordinate sets - string tcsetname (""); + string tcsetname; if (materials != NULL && tcinput != NULL) { - daeegg_cat.debug() << "Assigning texcoord set " << tcinput->GetSet() << " to semantic '" << FROM_FSTRING(polygons->GetMaterialSemantic()) << "'\n"; - tcsetname = materials->get_uvset_name(FROM_FSTRING(polygons->GetMaterialSemantic()), FUDaeGeometryInput::TEXCOORD, tcinput->GetSet()); + if (daeegg_cat.is_debug()) { + daeegg_cat.debug() + << "Assigning texcoord set " << tcinput->GetSet() + << " to semantic '" << material_semantic << "'\n"; + } + tcsetname = materials->get_uvset_name(material_semantic, + FUDaeGeometryInput::TEXCOORD, tcinput->GetSet()); } - string tbsetname (""); + string tbsetname; if (materials != NULL && binput != NULL) { - daeegg_cat.debug() << "Assigning texbinormal set " << binput->GetSet() << " to semantic '" << FROM_FSTRING(polygons->GetMaterialSemantic()) << "'\n"; - tbsetname = materials->get_uvset_name(FROM_FSTRING(polygons->GetMaterialSemantic()), FUDaeGeometryInput::TEXBINORMAL, binput->GetSet()); + if (daeegg_cat.is_debug()) { + daeegg_cat.debug() + << "Assigning texbinormal set " << binput->GetSet() + << " to semantic '" << material_semantic << "'\n"; + } + tbsetname = materials->get_uvset_name(material_semantic, + FUDaeGeometryInput::TEXBINORMAL, binput->GetSet()); } - string ttsetname (""); + string ttsetname; if (materials != NULL && tinput != NULL) { - daeegg_cat.debug() << "Assigning textangent set " << tinput->GetSet() << " to semantic '" << FROM_FSTRING(polygons->GetMaterialSemantic()) << "'\n"; - ttsetname = materials->get_uvset_name(FROM_FSTRING(polygons->GetMaterialSemantic()), FUDaeGeometryInput::TEXTANGENT, tinput->GetSet()); + if (daeegg_cat.is_debug()) { + daeegg_cat.debug() + << "Assigning textangent set " << tinput->GetSet() + << " to semantic '" << material_semantic << "'\n"; + } + ttsetname = materials->get_uvset_name(material_semantic, + FUDaeGeometryInput::TEXTANGENT, tinput->GetSet()); } // Loop through the indices and add the vertices. for (size_t ix = 0; ix < pinput->GetIndexCount(); ++ix) { PT_EggVertex vertex = mesh_pool->make_new_vertex(); const float* data = &vsource->GetData()[indices[ix]*3]; vertex->set_pos(LPoint3d(data[0], data[1], data[2])); + + if (character != NULL) { + // If this is skinned geometry, add the vertex influences. + character->influence_vertex(indices[ix], vertex); + } + // Process the normal if (nsource != NULL && ninput != NULL) { assert(nsource->GetStride() == 3); @@ -469,26 +662,26 @@ void DAEToEggConverter::process_mesh(PT(EggGroup) parent, const FCDGeometryMesh* PT(EggPrimitive) primitive = NULL; // Create a primitive that matches the fcollada type switch (polygons->GetPrimitiveType()) { - case FCDGeometryPolygons::LINES: - primitive = new EggLine(); - break; - case FCDGeometryPolygons::POLYGONS: - primitive = new EggPolygon(); - break; - case FCDGeometryPolygons::TRIANGLE_FANS: - primitive = new EggTriangleFan(); - break; - case FCDGeometryPolygons::TRIANGLE_STRIPS: - primitive = new EggTriangleStrip(); - break; - case FCDGeometryPolygons::POINTS: - primitive = new EggPoint(); - break; - case FCDGeometryPolygons::LINE_STRIPS: - daeegg_cat.warning() << "Linestrips not yet supported!" << endl; - break; - default: - daeegg_cat.warning() << "Unsupported primitive type found!" << endl; + case FCDGeometryPolygons::LINES: + primitive = new EggLine(); + break; + case FCDGeometryPolygons::POLYGONS: + primitive = new EggPolygon(); + break; + case FCDGeometryPolygons::TRIANGLE_FANS: + primitive = new EggTriangleFan(); + break; + case FCDGeometryPolygons::TRIANGLE_STRIPS: + primitive = new EggTriangleStrip(); + break; + case FCDGeometryPolygons::POINTS: + primitive = new EggPoint(); + break; + case FCDGeometryPolygons::LINE_STRIPS: + daeegg_cat.warning() << "Linestrips not yet supported!" << endl; + break; + default: + daeegg_cat.warning() << "Unsupported primitive type found!" << endl; } if (primitive != NULL) { primitive_holders[gr]->add_child(primitive); @@ -506,7 +699,8 @@ void DAEToEggConverter::process_mesh(PT(EggGroup) parent, const FCDGeometryMesh* delete[] primitive_holders; } -void DAEToEggConverter::process_spline(PT(EggGroup) parent, const string group_name, FCDGeometrySpline* geometry_spline) { +void DAEToEggConverter:: +process_spline(EggGroup *parent, const string group_name, FCDGeometrySpline* geometry_spline) { assert(geometry_spline != NULL); PT(EggGroup) result = new EggGroup(group_name); parent->add_child(result); @@ -521,7 +715,8 @@ void DAEToEggConverter::process_spline(PT(EggGroup) parent, const string group_n } } -void DAEToEggConverter::process_spline(PT(EggGroup) parent, const FCDSpline* spline) { +void DAEToEggConverter:: +process_spline(EggGroup *parent, const FCDSpline* spline) { assert(spline != NULL); nassertv(spline->GetSplineType() == FUDaeSplineType::NURBS); // Now load in the nurbs curve to the egg library @@ -542,70 +737,26 @@ void DAEToEggConverter::process_spline(PT(EggGroup) parent, const FCDSpline* spl } } -void DAEToEggConverter::process_controller(PT(EggGroup) parent, const FCDControllerInstance* instance) { +void DAEToEggConverter:: +process_controller(EggGroup *parent, const FCDControllerInstance *instance) { assert(instance != NULL); - const FCDController* controller = (const FCDController*) instance->GetEntity(); + const FCDController* controller = (const FCDController *)instance->GetEntity(); assert(controller != NULL); - PT(EggVertexPool) vertex_pool = NULL; - // Add the skin geometry - const FCDGeometry* geometry = controller->GetBaseGeometry(); - if (geometry != NULL) { - if (geometry->IsMesh()) { - process_mesh(parent, geometry->GetMesh(), new DaeMaterials((const FCDGeometryInstance*) instance)); + + if (get_animation_convert() == AC_none) { + // If we're exporting a static mesh, export the base geometry as-is. + const FCDGeometryMesh *mesh = controller->GetBaseGeometry()->GetMesh(); + if (mesh != NULL) { + PT(DaeMaterials) materials = new DaeMaterials(instance); daeegg_cat.spam() << "Processing mesh for controller\n"; - if (_vertex_pools.count(FROM_FSTRING(geometry->GetMesh()->GetDaeId()))) { - daeegg_cat.debug() << "Using vertex pool " << FROM_FSTRING(geometry->GetMesh()->GetDaeId()) << "\n"; - vertex_pool = _vertex_pools[FROM_FSTRING(geometry->GetMesh()->GetDaeId())]; - } - } - if (geometry->IsSpline()) { - process_spline(parent, FROM_FSTRING(geometry->GetName()), const_cast (geometry->GetSpline())); - } - } - // Add the joint hierarchy -#if FCOLLADA_VERSION < 0x00030005 - FCDSceneNodeList roots = (const_cast (instance))->FindSkeletonNodes(); -#else - FCDSceneNodeList roots; - (const_cast (instance))->FindSkeletonNodes(roots); -#endif - for (FCDSceneNodeList::iterator it = roots.begin(); it != roots.end(); ++it) { - process_node(DCAST(EggGroupNode, parent), *it, true); - } - if (controller->IsSkin()) { - // Load in the vertex influences first - pmap > > influences; - if (vertex_pool) { - for (size_t in = 0; in < controller->GetSkinController()->GetInfluenceCount(); ++in) { - assert(vertex_pool->has_vertex(in)); - for (size_t pa = 0; pa < controller->GetSkinController()->GetVertexInfluence(in)->GetPairCount(); ++pa) { - const FCDJointWeightPair* jwpair = controller->GetSkinController()->GetVertexInfluence(in)->GetPair(pa); - influences[jwpair->jointIndex].push_back(pair (vertex_pool->get_vertex(in), jwpair->weight)); - } - } - } - // Loop through the joints in the vertex influences - for (pmap > >::iterator it = influences.begin(); it != influences.end(); ++it) { - if (it->first == -1) { - daeegg_cat.warning() << "Ignoring vertex influence with negative joint index\n"; - //FIXME: Why are there joints with index -1 - } else { - const string joint_id = FROM_FSTRING(controller->GetSkinController()->GetJoint(it->first)->GetId()); - //TODO: what if the joints have just not been defined yet? - if (_joints.count(joint_id) > 0) { - if (_joints[joint_id]) { - for (pvector >::iterator vi = it->second.begin(); vi != it->second.end(); ++vi) { - _joints[joint_id]->ref_vertex(vi->first, vi->second); - } - } else { - daeegg_cat.warning() << "Unprocessed joint being referenced: '" << joint_id << "'" << endl; - } - } else { - daeegg_cat.warning() << "Unknown joint being referenced: '" << joint_id << "'" << endl; - } - } + process_mesh(parent, mesh, materials); } + } else { + // Add a character for this to the table, the mesh is processed later + PT(DaeCharacter) character = new DaeCharacter(parent, instance); + _characters.push_back(character); } + if (controller->IsMorph()) { assert(controller != NULL); const FCDMorphController* morph_controller = controller->GetMorphController(); @@ -628,28 +779,25 @@ void DAEToEggConverter::process_controller(PT(EggGroup) parent, const FCDControl morph->add_child(target); } } - - // Get a for the character and add it to the table - PT(DaeCharacter) character = new DaeCharacter(parent->get_name(), instance); - _table->add_child(character->as_egg_bundle()); } -void DAEToEggConverter::process_extra(PT(EggGroup) group, const FCDExtra* extra) { +void DAEToEggConverter:: +process_extra(EggGroup *group, const FCDExtra* extra) { if (extra == NULL) { return; } nassertv(group != NULL); - + const FCDEType* etype = extra->GetDefaultType(); if (etype == NULL) { return; } - + const FCDENode* enode = (const FCDENode*) etype->FindTechnique("PANDA3D"); if (enode == NULL) { return; } - + FCDENodeList tags; enode->FindChildrenNodes("param", tags); for (FCDENodeList::iterator it = tags.begin(); it != tags.end(); ++it) { @@ -660,18 +808,45 @@ void DAEToEggConverter::process_extra(PT(EggGroup) group, const FCDExtra* extra) } } -LMatrix4d DAEToEggConverter::convert_matrix(const FMMatrix44& matrix) { - LMatrix4d result = LMatrix4d::zeros_mat(); - for (char x = 0; x < 4; ++x) { - for (char y = 0; y < 4; ++y) { - result(x, y) = matrix[x][y]; - } - } - return result; +LMatrix4d DAEToEggConverter:: +convert_matrix(const FMMatrix44 &matrix) { + return LMatrix4d( + matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3], + matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3], + matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3], + matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]); } -void DAEToEggConverter::apply_transform(const PT(EggGroup) to, const FCDTransform* from) { +void DAEToEggConverter:: +apply_transform(EggGroup *to, const FCDTransform* from) { assert(from != NULL); assert(to != NULL); - to->set_transform3d(convert_matrix(from->ToMatrix()) * to->get_transform3d()); + //to->set_transform3d(convert_matrix(from->ToMatrix()) * to->get_transform3d()); + switch (from->GetType()) { + case FCDTransform::TRANSLATION: + { + const FCDTTranslation *trans = (const FCDTTranslation *)from; + to->add_translate3d(TO_VEC3(trans->GetTranslation())); + } + break; + + case FCDTransform::ROTATION: + { + const FCDTRotation *rot = (const FCDTRotation *)from; + to->add_rotate3d(rot->GetAngle(), TO_VEC3(rot->GetAxis())); + } + break; + + case FCDTransform::SCALE: + { + const FCDTScale *scale = (const FCDTScale *)from; + to->add_scale3d(TO_VEC3(scale->GetScale())); + } + break; + + default: + // Either a matrix, or something we can't handle. + to->add_matrix4(convert_matrix(from->ToMatrix())); + break; + } } diff --git a/pandatool/src/daeegg/daeToEggConverter.h b/pandatool/src/daeegg/daeToEggConverter.h index f3384e93ee..e2c29a1fa1 100755 --- a/pandatool/src/daeegg/daeToEggConverter.h +++ b/pandatool/src/daeegg/daeToEggConverter.h @@ -35,6 +35,7 @@ #include "FMath/FMMatrix44.h" #include "daeMaterials.h" +#include "daeCharacter.h" #include "pvector.h" // Include last //////////////////////////////////////////////////////////////////// @@ -47,39 +48,41 @@ public: DAEToEggConverter(); DAEToEggConverter(const DAEToEggConverter ©); ~DAEToEggConverter(); - + virtual SomethingToEggConverter *make_copy(); - + virtual string get_name() const; virtual string get_extension() const; - + virtual bool convert_file(const Filename &filename); + virtual DistanceUnit get_input_units(); bool _invert_transparency; private: + string _unit_name; + double _unit_meters; PT(EggTable) _table; FCDocument* _document; FUErrorSimpleHandler* _error_handler; - pmap _joints; - pmap _vertex_pools; - pvector _skeletons; - int _frame_rate; - + DaeCharacter::JointMap _joints; + + typedef pvector Characters; + Characters _characters; + void process_asset(); - void preprocess(const FCDSceneNode* node = NULL); - void process_node(PT(EggGroupNode) parent, const FCDSceneNode* node, bool forced = false); - void process_instance(PT(EggGroup) parent, const FCDEntityInstance* instance); - void process_mesh(PT(EggGroup) parent, const FCDGeometryMesh* mesh, PT(DaeMaterials) materials); - void process_spline(PT(EggGroup) parent, const string group_name, FCDGeometrySpline* geometry_spline); - void process_spline(PT(EggGroup) parent, const FCDSpline* spline); - void process_controller(PT(EggGroup) parent, const FCDControllerInstance* instance); - //void process_table_joint(PT(EggTable) parent, FCDSceneNode* node); - void process_extra(PT(EggGroup) group, const FCDExtra* extra); - + void process_node(EggGroupNode *parent, const FCDSceneNode* node, bool forced = false); + void process_instance(EggGroup *parent, const FCDEntityInstance* instance); + void process_mesh(EggGroup *parent, const FCDGeometryMesh* mesh, + DaeMaterials *materials, DaeCharacter *character = NULL); + void process_spline(EggGroup *parent, const string group_name, FCDGeometrySpline* geometry_spline); + void process_spline(EggGroup *parent, const FCDSpline* spline); + void process_controller(EggGroup *parent, const FCDControllerInstance* instance); + void process_extra(EggGroup *group, const FCDExtra* extra); + static LMatrix4d convert_matrix(const FMMatrix44& matrix); - void apply_transform(const PT(EggGroup) to, const FCDTransform* from); - + void apply_transform(EggGroup *to, const FCDTransform* from); + friend class DaeCharacter; }; diff --git a/pandatool/src/daeprogs/daeToEgg.cxx b/pandatool/src/daeprogs/daeToEgg.cxx index 503d1af33a..38a0eb9cdb 100755 --- a/pandatool/src/daeprogs/daeToEgg.cxx +++ b/pandatool/src/daeprogs/daeToEgg.cxx @@ -26,6 +26,7 @@ DAEToEgg:: DAEToEgg(): SomethingToEgg("COLLADA", ".dae") { + add_animation_options(); add_units_options(); add_normals_options(); add_transform_options(); @@ -42,6 +43,7 @@ DAEToEgg(): ("This program converts .dae files (COLLADA Digital Asset Exchange) to .egg."); _coordinate_system = CS_yup_right; + _animation_convert = AC_both; } //////////////////////////////////////////////////////////////////// @@ -51,6 +53,12 @@ DAEToEgg(): //////////////////////////////////////////////////////////////////// void DAEToEgg:: run() { + if (_animation_convert != AC_both && _animation_convert != AC_none && + _animation_convert != AC_chan && _animation_convert != AC_model) { + cerr << "Unsupported animation convert option.\n"; + exit(1); + } + nout << "Reading " << _input_filename << "\n"; _data->set_coordinate_system(_coordinate_system); From c0e4de3df70f6ae19f660e4791c258d37e7f4adb Mon Sep 17 00:00:00 2001 From: 09th Date: Tue, 24 Feb 2015 19:58:14 +0100 Subject: [PATCH 13/32] Fix bam2egg issue with animated models --- panda/src/egg2pg/eggSaver.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/egg2pg/eggSaver.cxx b/panda/src/egg2pg/eggSaver.cxx index 83f0d2aaeb..8086b33aaf 100755 --- a/panda/src/egg2pg/eggSaver.cxx +++ b/panda/src/egg2pg/eggSaver.cxx @@ -347,7 +347,7 @@ convert_character_bundle(PartGroup *bundleNode, EggGroupNode *egg_parent, Charac CharacterJoint *character_joint = DCAST(CharacterJoint, bundleNode); LMatrix4 transformf; - character_joint->get_net_transform(transformf); + character_joint->get_transform(transformf); LMatrix4d transformd(LCAST(double, transformf)); EggGroup *joint = new EggGroup(bundleNode->get_name()); joint->add_matrix4(transformd); From 46ddd46c5cee7181884dc5541b591474a5714c37 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 24 Feb 2015 21:40:55 +0100 Subject: [PATCH 14/32] Support materials in bam2egg --- panda/src/egg2pg/eggSaver.cxx | 49 ++++++++++++++++++++++++++++++++++- panda/src/egg2pg/eggSaver.h | 3 ++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/panda/src/egg2pg/eggSaver.cxx b/panda/src/egg2pg/eggSaver.cxx index 8086b33aaf..051c3b6f54 100755 --- a/panda/src/egg2pg/eggSaver.cxx +++ b/panda/src/egg2pg/eggSaver.cxx @@ -22,6 +22,7 @@ #include "transformState.h" #include "colorScaleAttrib.h" #include "colorAttrib.h" +#include "materialAttrib.h" #include "textureAttrib.h" #include "cullFaceAttrib.h" #include "transparencyAttrib.h" @@ -577,6 +578,13 @@ convert_primitive(const GeomVertexData *vertex_data, } } + // Check for a material. + EggMaterial *egg_mat = (EggMaterial *)NULL; + const MaterialAttrib *ma = DCAST(MaterialAttrib, net_state->get_attrib(MaterialAttrib::get_class_type())); + if (ma != (const MaterialAttrib *)NULL) { + egg_mat = get_egg_material(ma->get_material()); + } + // Check for a texture. EggTexture *egg_tex = (EggTexture *)NULL; const TextureAttrib *ta = DCAST(TextureAttrib, net_state->get_attrib(TextureAttrib::get_class_type())); @@ -703,11 +711,15 @@ convert_primitive(const GeomVertexData *vertex_data, // Huh, an unknown geometry type. return; } - + for (int i = 0; i < num_primitives; ++i) { PT(EggPrimitive) egg_prim = (*make_func)(); egg_parent->add_child(egg_prim); + + if (egg_mat != (EggMaterial *)NULL) { + egg_prim->set_material(egg_mat); + } if (egg_tex != (EggTexture *)NULL) { egg_prim->set_texture(egg_tex); } @@ -947,6 +959,41 @@ apply_tag(EggGroup *egg_group, PandaNode *node, const string &tag) { return true; } +//////////////////////////////////////////////////////////////////// +// Function: EggSaver::get_egg_material +// Access: Private +// Description: Returns an EggMaterial pointer that corresponds to +// the indicated Material. +//////////////////////////////////////////////////////////////////// +EggMaterial *EggSaver:: +get_egg_material(Material *mat) { + if (mat != (Material *)NULL) { + EggMaterial temp(mat->get_name()); + if (mat->has_ambient()) { + temp.set_amb(mat->get_ambient()); + } + + if (mat->has_diffuse()) { + temp.set_diff(mat->get_diffuse()); + } + + if (mat->has_specular()) { + temp.set_spec(mat->get_specular()); + } + + if (mat->has_emission()) { + temp.set_emit(mat->get_emission()); + } + + temp.set_shininess(mat->get_shininess()); + temp.set_local(mat->get_local()); + + return _materials.create_unique_material(temp, ~EggMaterial::E_mref_name); + } + + return NULL; +} + //////////////////////////////////////////////////////////////////// // Function: EggSaver::get_egg_texture // Access: Private diff --git a/panda/src/egg2pg/eggSaver.h b/panda/src/egg2pg/eggSaver.h index c565b258af..0dfbdc8838 100755 --- a/panda/src/egg2pg/eggSaver.h +++ b/panda/src/egg2pg/eggSaver.h @@ -92,6 +92,7 @@ private: bool apply_tags(EggGroup *egg_group, PandaNode *node); bool apply_tag(EggGroup *egg_group, PandaNode *node, const string &tag); + EggMaterial *get_egg_material(Material *tex); EggTexture *get_egg_texture(Texture *tex); static EggPrimitive *make_egg_polygon(); @@ -102,8 +103,8 @@ private: PT(EggData) _data; PT(EggVertexPool) _vpool; - EggTextureCollection _textures; EggMaterialCollection _materials; + EggTextureCollection _textures; }; #include "eggSaver.I" From 8dbe681143f7e658ed257dc25a67bdf4dbdc9e3d Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 24 Feb 2015 23:51:00 +0100 Subject: [PATCH 15/32] Fix bug with Collide flag "polyset" and nested elements --- panda/src/collide/collisionBox.cxx | 16 +++++++----- panda/src/egg2pg/eggLoader.cxx | 41 ++++++++++++++---------------- panda/src/pgraph/polylightNode.I | 5 ++-- panda/src/pgraph/polylightNode.cxx | 24 +++++++++++++++++ panda/src/pgraph/polylightNode.h | 8 +++--- 5 files changed, 59 insertions(+), 35 deletions(-) diff --git a/panda/src/collide/collisionBox.cxx b/panda/src/collide/collisionBox.cxx index f467d73a8b..e1bdf03970 100644 --- a/panda/src/collide/collisionBox.cxx +++ b/panda/src/collide/collisionBox.cxx @@ -144,15 +144,19 @@ test_intersection(const CollisionEntry &entry) const { //////////////////////////////////////////////////////////////////// void CollisionBox:: xform(const LMatrix4 &mat) { + _min = _min * mat; + _max = _max * mat; _center = _center * mat; - for(int v = 0; v < 8; v++) + for(int v = 0; v < 8; v++) { _vertex[v] = _vertex[v] * mat; - for(int p = 0; p < 6 ; p++) + } + for(int p = 0; p < 6 ; p++) { _planes[p] = set_plane(p); - _x = _vertex[0].get_x()-_center.get_x(); - _y = _vertex[0].get_y()-_center.get_y(); - _z = _vertex[0].get_z()-_center.get_z(); - _radius = sqrt( _x*_x + _y*_y + _z*_z ); + } + _x = _vertex[0].get_x() - _center.get_x(); + _y = _vertex[0].get_y() - _center.get_y(); + _z = _vertex[0].get_z() - _center.get_z(); + _radius = sqrt(_x * _x + _y * _y + _z * _z); setup_box(); mark_viz_stale(); mark_internal_bounds_stale(); diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index 8cafc8dced..ae3be83199 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -1865,6 +1865,10 @@ make_node(EggGroup *egg_group, PandaNode *parent) { node = new CollisionNode(egg_group->get_name()); make_collision_solids(egg_group, egg_group, (CollisionNode *)node.p()); + + // Transform all of the collision solids into local space. + node->xform(LCAST(PN_stdfloat, egg_group->get_vertex_to_node())); + if ((egg_group->get_collide_flags() & EggGroup::CF_keep) != 0) { // If we also specified to keep the geometry, continue the // traversal. In this case, we create a new PandaNode to be the @@ -1925,8 +1929,11 @@ make_node(EggGroup *egg_group, PandaNode *parent) { pnode->set_pos(center); pnode->set_color(color); pnode->set_radius(radius); + + pnode->xform(LCAST(PN_stdfloat, egg_group->get_vertex_to_node())); + node = pnode; - + } else if (egg_group->get_switch_flag()) { if (egg_group->get_switch_fps() != 0.0) { // Create a sequence node. @@ -2790,7 +2797,6 @@ find_first_polygon(EggGroup *egg_group) { bool EggLoader:: make_sphere(EggGroup *egg_group, EggGroup::CollideFlags flags, LPoint3 ¢er, PN_stdfloat &radius, LColor &color) { - bool success=false; EggGroup *geom_group = find_collision_geometry(egg_group, flags); if (geom_group != (EggGroup *)NULL) { // Collect all of the vertices. @@ -2822,15 +2828,12 @@ make_sphere(EggGroup *egg_group, EggGroup::CollideFlags flags, d_center /= (double)num_vertices; //egg2pg_cat.debug() << "make_sphere d_center: " << d_center << "\n"; - LMatrix4d mat = egg_group->get_vertex_to_node(); - d_center = d_center * mat; - // And the furthest vertex determines the radius. double radius2 = 0.0; for (vi = vertices.begin(); vi != vertices.end(); ++vi) { EggVertex *vtx = (*vi); LPoint3d p3 = vtx->get_pos3(); - LVector3d v = p3 * mat - d_center; + LVector3d v = p3 - d_center; radius2 = max(radius2, v.length_squared()); } @@ -2841,10 +2844,10 @@ make_sphere(EggGroup *egg_group, EggGroup::CollideFlags flags, vi = vertices.begin(); EggVertex *clr_vtx = (*vi); color = clr_vtx->get_color(); - success = true; + return true; } } - return success; + return false; } //////////////////////////////////////////////////////////////////// @@ -2900,9 +2903,8 @@ make_box(EggGroup *egg_group, EggGroup::CollideFlags flags, max(max_pd[2], pos[2])); } - LMatrix4d mat = egg_group->get_vertex_to_node(); - min_p = LCAST(PN_stdfloat, min_pd * mat); - max_p = LCAST(PN_stdfloat, max_pd * mat); + min_p = LCAST(PN_stdfloat, min_pd); + max_p = LCAST(PN_stdfloat, max_pd); return (min_pd != max_pd); } return false; @@ -3170,7 +3172,6 @@ make_collision_tube(EggGroup *egg_group, CollisionNode *cnode, // also determine the centroid). We compute this in node space. size_t num_vertices = vertices.size(); if (num_vertices != 0) { - LMatrix4d mat = egg_group->get_vertex_to_node(); pvector vpos; vpos.reserve(num_vertices); @@ -3178,7 +3179,7 @@ make_collision_tube(EggGroup *egg_group, CollisionNode *cnode, pset::const_iterator vi; for (vi = vertices.begin(); vi != vertices.end(); ++vi) { EggVertex *vtx = (*vi); - LPoint3d pos = vtx->get_pos3() * mat; + const LPoint3d &pos = vtx->get_pos3(); vpos.push_back(pos); center += pos; } @@ -3420,20 +3421,18 @@ create_collision_plane(EggPolygon *egg_poly, EggGroup *parent_group) { << "\n"; } - LMatrix4d mat = egg_poly->get_vertex_to_node(); - pvector vertices; if (!egg_poly->empty()) { EggPolygon::const_iterator vi; vi = egg_poly->begin(); - LVertexd vert = (*vi)->get_pos3() * mat; + LVertexd vert = (*vi)->get_pos3(); vertices.push_back(LCAST(PN_stdfloat, vert)); LVertexd last_vert = vert; ++vi; while (vi != egg_poly->end()) { - vert = (*vi)->get_pos3() * mat; + vert = (*vi)->get_pos3(); if (!vert.almost_equal(last_vert)) { vertices.push_back(LCAST(PN_stdfloat, vert)); } @@ -3461,7 +3460,6 @@ void EggLoader:: create_collision_polygons(CollisionNode *cnode, EggPolygon *egg_poly, EggGroup *parent_group, EggGroup::CollideFlags flags) { - LMatrix4d mat = egg_poly->get_vertex_to_node(); PT(EggGroup) group = new EggGroup; @@ -3489,13 +3487,13 @@ create_collision_polygons(CollisionNode *cnode, EggPolygon *egg_poly, EggPolygon::const_iterator vi; vi = poly->begin(); - LVertexd vert = (*vi)->get_pos3() * mat; + LVertexd vert = (*vi)->get_pos3(); vertices.push_back(LCAST(PN_stdfloat, vert)); LVertexd last_vert = vert; ++vi; while (vi != poly->end()) { - vert = (*vi)->get_pos3() * mat; + vert = (*vi)->get_pos3(); if (!vert.almost_equal(last_vert)) { vertices.push_back(LCAST(PN_stdfloat, vert)); } @@ -3513,12 +3511,11 @@ create_collision_polygons(CollisionNode *cnode, EggPolygon *egg_poly, if (cspoly->is_valid()) { apply_collision_flags(cspoly, flags); cnode->add_solid(cspoly); - } + } } } } - //////////////////////////////////////////////////////////////////// // Function: EggLoader::create_collision_floor_mesh // Access: Private diff --git a/panda/src/pgraph/polylightNode.I b/panda/src/pgraph/polylightNode.I index 4571035db7..c9b7de7c6d 100755 --- a/panda/src/pgraph/polylightNode.I +++ b/panda/src/pgraph/polylightNode.I @@ -85,11 +85,10 @@ disable(){ // Description: Set this light's position //////////////////////////////////////////////////////////////////// INLINE void PolylightNode:: -set_pos(const LVecBase3 &position){ +set_pos(const LPoint3 &position) { _position = position; } - //////////////////////////////////////////////////////////////////// // Function: PolylightNode::set_pos // Access: Published @@ -107,7 +106,7 @@ set_pos(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z){ // Access: Published // Description: Returns position as a LPoint3 //////////////////////////////////////////////////////////////////// -INLINE LVecBase3 PolylightNode:: +INLINE LPoint3 PolylightNode:: get_pos() const { return _position; } diff --git a/panda/src/pgraph/polylightNode.cxx b/panda/src/pgraph/polylightNode.cxx index 1d2c87693c..8d383db018 100755 --- a/panda/src/pgraph/polylightNode.cxx +++ b/panda/src/pgraph/polylightNode.cxx @@ -65,6 +65,30 @@ make_copy() const { return new PolylightNode(*this); } +//////////////////////////////////////////////////////////////////// +// Function: PolylightNode::xform +// Access: Public, Virtual +// Description: Transforms the contents of this node by the indicated +// matrix, if it means anything to do so. For most +// kinds of nodes, this does nothing. +//////////////////////////////////////////////////////////////////// +void PolylightNode:: +xform(const LMatrix4 &mat) { + nassertv(!mat.is_nan()); + + if (mat.almost_equal(LMatrix4::ident_mat())) { + return; + } + + _position = _position * mat; + + // This is a little cheesy and fails miserably in the presence of a + // non-uniform scale. + LVector3 radius_v = LVector3(_radius, 0.0f, 0.0f) * mat; + _radius = length(radius_v); + mark_internal_bounds_stale(); +} + //////////////////////////////////////////////////////////////////// // Function: PolylightNode::Constructor // Access: Public diff --git a/panda/src/pgraph/polylightNode.h b/panda/src/pgraph/polylightNode.h index 8eb3aacbee..caacbecf57 100755 --- a/panda/src/pgraph/polylightNode.h +++ b/panda/src/pgraph/polylightNode.h @@ -58,9 +58,9 @@ PUBLISHED: PolylightNode(const string &name); INLINE void enable(); INLINE void disable(); - INLINE void set_pos(const LVecBase3 &position); + INLINE void set_pos(const LPoint3 &position); INLINE void set_pos(PN_stdfloat x,PN_stdfloat y, PN_stdfloat z); - INLINE LVecBase3 get_pos() const; + INLINE LPoint3 get_pos() const; INLINE void set_color(const LColor &color); INLINE void set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b); INLINE LColor get_color() const; @@ -100,11 +100,11 @@ PUBLISHED: public: LColor flicker() const; virtual PandaNode *make_copy() const; + virtual void xform(const LMatrix4 &mat); - private: bool _enabled; - LVecBase3 _position; + LPoint3 _position; LColor _color; PN_stdfloat _radius; Attenuation_Type _attenuation_type; From 894423ace4961ac6abc53512a8e05f9c2b5e85b7 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Tue, 24 Feb 2015 16:06:40 -0800 Subject: [PATCH 16/32] ffmpeg: Don't use internal SWR_CH_MAX macro. --- panda/src/ffmpeg/ffmpegAudioCursor.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/panda/src/ffmpeg/ffmpegAudioCursor.cxx b/panda/src/ffmpeg/ffmpegAudioCursor.cxx index 5cddb016c8..4eab28e4b6 100644 --- a/panda/src/ffmpeg/ffmpegAudioCursor.cxx +++ b/panda/src/ffmpeg/ffmpegAudioCursor.cxx @@ -313,8 +313,7 @@ reload_buffer() { #ifdef HAVE_SWRESAMPLE if (_resample_ctx) { // Resample the data to signed 16-bit sample format. - uint8_t* out[SWR_CH_MAX] = {(uint8_t*) _buffer, NULL}; - bufsize = swr_convert(_resample_ctx, out, _buffer_size / 2, (const uint8_t**)_frame->extended_data, _frame->nb_samples); + bufsize = swr_convert(_resample_ctx, (uint8_t **)&_buffer, _buffer_size / 2, (const uint8_t**)_frame->extended_data, _frame->nb_samples); bufsize *= _audio_channels * 2; } else #endif From 903966371c861a3084174103fa3407bc2f6bbad9 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Tue, 24 Feb 2015 15:41:05 -0800 Subject: [PATCH 17/32] general: Fix missing includes. --- panda/src/gobj/samplerContext.h | 1 + panda/src/gobj/samplerState.h | 1 + panda/src/pgraph/cullBinManager.h | 1 + panda/src/pgraph/shaderPool.cxx | 1 + 4 files changed, 4 insertions(+) diff --git a/panda/src/gobj/samplerContext.h b/panda/src/gobj/samplerContext.h index 61a876d405..a51157ccc0 100644 --- a/panda/src/gobj/samplerContext.h +++ b/panda/src/gobj/samplerContext.h @@ -18,6 +18,7 @@ #include "pandabase.h" #include "adaptiveLru.h" +#include "simpleLru.h" #include "samplerState.h" #include "savedContext.h" diff --git a/panda/src/gobj/samplerState.h b/panda/src/gobj/samplerState.h index d5c10d6a1c..de3e4d6cf5 100644 --- a/panda/src/gobj/samplerState.h +++ b/panda/src/gobj/samplerState.h @@ -21,6 +21,7 @@ #include "namable.h" #include "luse.h" #include "numeric_types.h" +#include "bamReader.h" #include "config_gobj.h" class FactoryParams; diff --git a/panda/src/pgraph/cullBinManager.h b/panda/src/pgraph/cullBinManager.h index 4e6adf0821..6d29d9e1f4 100644 --- a/panda/src/pgraph/cullBinManager.h +++ b/panda/src/pgraph/cullBinManager.h @@ -20,6 +20,7 @@ #include "cullBinEnums.h" #include "pointerTo.h" #include "pvector.h" +#include "epvector.h" #include "pmap.h" #include "vector_int.h" #include "pStatCollector.h" diff --git a/panda/src/pgraph/shaderPool.cxx b/panda/src/pgraph/shaderPool.cxx index 1ca9ddbe00..5476960c6e 100644 --- a/panda/src/pgraph/shaderPool.cxx +++ b/panda/src/pgraph/shaderPool.cxx @@ -18,6 +18,7 @@ #include "virtualFileSystem.h" #include "loader.h" #include "shader.h" +#include "string_utils.h" ShaderPool *ShaderPool::_global_ptr = (ShaderPool *)NULL; From f0b3e08e9c75e5cdcd98c0f3142469918d1d2fd5 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Tue, 24 Feb 2015 16:22:37 -0800 Subject: [PATCH 18/32] ffmpeg: Use av_frame_* instead of deprecated avcodec_*_frame functions beginning with lavc 55.45.101. --- panda/src/ffmpeg/ffmpegAudioCursor.cxx | 8 +++++++- panda/src/ffmpeg/ffmpegVideoCursor.cxx | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/panda/src/ffmpeg/ffmpegAudioCursor.cxx b/panda/src/ffmpeg/ffmpegAudioCursor.cxx index 4eab28e4b6..a33db26b6f 100644 --- a/panda/src/ffmpeg/ffmpegAudioCursor.cxx +++ b/panda/src/ffmpeg/ffmpegAudioCursor.cxx @@ -148,7 +148,11 @@ FfmpegAudioCursor(FfmpegAudio *src) : _can_seek = true; _can_seek_fast = true; +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 59, 100) + _frame = av_frame_alloc(); +#else _frame = avcodec_alloc_frame(); +#endif _packet = new AVPacket; _buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE / 2; @@ -194,7 +198,9 @@ FfmpegAudioCursor:: void FfmpegAudioCursor:: cleanup() { if (_frame) { -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 59, 100) +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 45, 101) + av_frame_free(&_frame); +#elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 59, 100) avcodec_free_frame(&_frame); #else av_free(&_frame); diff --git a/panda/src/ffmpeg/ffmpegVideoCursor.cxx b/panda/src/ffmpeg/ffmpegVideoCursor.cxx index a02dac184b..87b3b48395 100644 --- a/panda/src/ffmpeg/ffmpegVideoCursor.cxx +++ b/panda/src/ffmpeg/ffmpegVideoCursor.cxx @@ -94,8 +94,13 @@ init_from(FfmpegVideo *source) { PIX_FMT_BGR24, SWS_BILINEAR | SWS_PRINT_INFO, NULL, NULL, NULL); #endif // HAVE_SWSCALE +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 59, 100) + _frame = av_frame_alloc(); + _frame_out = av_frame_alloc(); +#else _frame = avcodec_alloc_frame(); _frame_out = avcodec_alloc_frame(); +#endif if ((_frame == 0)||(_frame_out == 0)) { cleanup(); From 7a6aa7bfae8704d598146241a00ed0b36bfd9ca5 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 25 Feb 2015 01:25:19 +0100 Subject: [PATCH 19/32] Implement ParamNodePath; fix circular include issue in shaderInput.h --- panda/src/pgraph/Sources.pp | 3 + panda/src/pgraph/config_pgraph.cxx | 2 + panda/src/pgraph/nodePath.h | 4 +- panda/src/pgraph/p3pgraph_composite3.cxx | 1 + panda/src/pgraph/paramNodePath.I | 60 +++++++++++++ panda/src/pgraph/paramNodePath.cxx | 108 +++++++++++++++++++++++ panda/src/pgraph/paramNodePath.h | 75 ++++++++++++++++ panda/src/pgraph/shaderInput.I | 27 ------ panda/src/pgraph/shaderInput.cxx | 32 ++++++- panda/src/pgraph/shaderInput.h | 8 +- 10 files changed, 284 insertions(+), 36 deletions(-) create mode 100644 panda/src/pgraph/paramNodePath.I create mode 100644 panda/src/pgraph/paramNodePath.cxx create mode 100644 panda/src/pgraph/paramNodePath.h diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index 51e0bdb0fa..838adc49b4 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -79,6 +79,7 @@ occluderNode.I occluderNode.h \ pandaNode.I pandaNode.h \ pandaNodeChain.I pandaNodeChain.h \ + paramNodePath.I paramNodePath.h \ planeNode.I planeNode.h \ polylightEffect.I polylightEffect.h \ polylightNode.I polylightNode.h \ @@ -184,6 +185,7 @@ occluderNode.cxx \ pandaNode.cxx \ pandaNodeChain.cxx \ + paramNodePath.cxx \ planeNode.cxx \ polylightEffect.cxx \ polylightNode.cxx \ @@ -286,6 +288,7 @@ pandaNode.I pandaNode.h \ pandaNode_ext.h pandaNode_ext.cxx \ pandaNodeChain.I pandaNodeChain.h \ + paramNodePath.I paramNodePath.h \ planeNode.I planeNode.h \ polylightEffect.I polylightEffect.h \ polylightNode.I polylightNode.h \ diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index 18b85ea77c..a79eb0c23d 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -60,6 +60,7 @@ #include "nodePath.h" #include "nodePathComponent.h" #include "pandaNode.h" +#include "paramNodePath.h" #include "planeNode.h" #include "polylightEffect.h" #include "polylightNode.h" @@ -436,6 +437,7 @@ init_libpgraph() { NodePathComponent::init_type(); PandaNode::init_type(); PandaNodePipelineReader::init_type(); + ParamNodePath::init_type(); PlaneNode::init_type(); PolylightNode::init_type(); PolylightEffect::init_type(); diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index f03580f255..d84519547d 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -38,6 +38,7 @@ #include "pta_LVecBase3.h" #include "pta_LVecBase2.h" #include "stl_compares.h" +#include "shaderInput.h" class NodePathCollection; class FindApproxPath; @@ -1008,9 +1009,6 @@ private: INLINE ostream &operator << (ostream &out, const NodePath &node_path); -// We have to put this down here, to work around a circular include. -#include "shaderInput.h" - #include "nodePath.I" #endif diff --git a/panda/src/pgraph/p3pgraph_composite3.cxx b/panda/src/pgraph/p3pgraph_composite3.cxx index b539fefcee..5b88a55d2f 100644 --- a/panda/src/pgraph/p3pgraph_composite3.cxx +++ b/panda/src/pgraph/p3pgraph_composite3.cxx @@ -21,6 +21,7 @@ #include "occluderNode.cxx" #include "pandaNode.cxx" #include "pandaNodeChain.cxx" +#include "paramNodePath.cxx" #include "planeNode.cxx" #include "polylightEffect.cxx" #include "polylightNode.cxx" diff --git a/panda/src/pgraph/paramNodePath.I b/panda/src/pgraph/paramNodePath.I new file mode 100644 index 0000000000..8d52ac5ad6 --- /dev/null +++ b/panda/src/pgraph/paramNodePath.I @@ -0,0 +1,60 @@ +// Filename: paramNodePath.I +// Created by: rdb (25Feb15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ParamNodePath::Constructor +// Access: Published +// Description: Creates a new ParamNodePath storing the given +// node path object. +//////////////////////////////////////////////////////////////////// +INLINE ParamNodePath:: +ParamNodePath(const NodePath &node_path) : + _node_path(node_path) +{ +} + +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: ParamNodePath::Move Constructor +// Access: Published +// Description: Creates a new ParamNodePath storing the given +// node path object. +//////////////////////////////////////////////////////////////////// +INLINE ParamNodePath:: +ParamNodePath(NodePath &&node_path) NOEXCEPT : + _node_path(move(node_path)) +{ +} +#endif // USE_MOVE_SEMANTICS + +//////////////////////////////////////////////////////////////////// +// Function: ParamNodePath::get_value_type +// Access: Published, Virtual +// Description: Returns NodePath::get_class_type(). +//////////////////////////////////////////////////////////////////// +INLINE TypeHandle ParamNodePath:: +get_value_type() const { + return NodePath::get_class_type(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamNodePath::get_value +// Access: Published +// Description: Retrieves the NodePath stored in the parameter. +//////////////////////////////////////////////////////////////////// +INLINE const NodePath &ParamNodePath:: +get_value() const { + return _node_path; +} diff --git a/panda/src/pgraph/paramNodePath.cxx b/panda/src/pgraph/paramNodePath.cxx new file mode 100644 index 0000000000..00fb5be24a --- /dev/null +++ b/panda/src/pgraph/paramNodePath.cxx @@ -0,0 +1,108 @@ +// Filename: paramNodePath.cxx +// Created by: rdb (25Feb15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "paramNodePath.h" +#include "dcast.h" +#include "pandaNode.h" + +TypeHandle ParamNodePath::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: ParamNodePath::output +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void ParamNodePath:: +output(ostream &out) const { + out << "node path " << _node_path; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamNodePath::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// ParamValue. +//////////////////////////////////////////////////////////////////// +void ParamNodePath:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamNodePath::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void ParamNodePath:: +write_datagram(BamWriter *manager, Datagram &dg) { + ParamValueBase::write_datagram(manager, dg); + + // We can't store a NodePath, so we store a pointer to the + // underlying node, and pray that there is an unambiguous path + // from the root to it. + if (_node_path.is_empty()) { + manager->write_pointer(dg, NULL); + } else { + manager->write_pointer(dg, _node_path.node()); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamNodePath::complete_pointers +// Access: Public, Virtual +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +//////////////////////////////////////////////////////////////////// +int ParamNodePath:: +complete_pointers(TypedWritable **p_list, BamReader *manager) { + int pi = ParamValueBase::complete_pointers(p_list, manager); + _node_path = NodePath(DCAST(PandaNode, p_list[pi++])); + + return pi; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamNodePath::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type ParamValue is encountered +// in the Bam file. It should create the ParamValue +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *ParamNodePath:: +make_from_bam(const FactoryParams ¶ms) { + ParamNodePath *param = new ParamNodePath; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + param->fillin(scan, manager); + + return param; +} + +//////////////////////////////////////////////////////////////////// +// Function: ParamNodePath::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new ParamValue. +//////////////////////////////////////////////////////////////////// +void ParamNodePath:: +fillin(DatagramIterator &scan, BamReader *manager) { + ParamValueBase::fillin(scan, manager); + manager->read_pointer(scan); +} diff --git a/panda/src/pgraph/paramNodePath.h b/panda/src/pgraph/paramNodePath.h new file mode 100644 index 0000000000..f1634c49ba --- /dev/null +++ b/panda/src/pgraph/paramNodePath.h @@ -0,0 +1,75 @@ +// Filename: paramNodePath.h +// Created by: rdb (25Feb15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef PARAMNODEPATH_H +#define PARAMNODEPATH_H + +#include "pandabase.h" +#include "paramValue.h" +#include "nodePath.h" + +//////////////////////////////////////////////////////////////////// +// Class : ParamNodePath +// Description : A class object for storing a NodePath as a parameter. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_GOBJ ParamNodePath : public ParamValueBase { +protected: + INLINE ParamNodePath() {}; + +PUBLISHED: + INLINE ParamNodePath(const NodePath &node_path); + +#ifdef USE_MOVE_SEMANTICS + INLINE ParamNodePath(NodePath &&node_path) NOEXCEPT; +#endif + + INLINE virtual TypeHandle get_value_type() const; + INLINE const NodePath &get_value() const; + + virtual void output(ostream &out) const; + +private: + NodePath _node_path; + +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); + virtual int complete_pointers(TypedWritable **plist, + BamReader *manager); + +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + void fillin(DatagramIterator &scan, BamReader *manager); + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + ParamValueBase::init_type(); + register_type(_type_handle, "ParamNodePath", + ParamValueBase::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +#include "paramNodePath.I" + +#endif diff --git a/panda/src/pgraph/shaderInput.I b/panda/src/pgraph/shaderInput.I index b75724abea..c7aed1de80 100644 --- a/panda/src/pgraph/shaderInput.I +++ b/panda/src/pgraph/shaderInput.I @@ -119,23 +119,6 @@ ShaderInput(CPT_InternalName name, ParamValueBase *param, int priority) : { } -//////////////////////////////////////////////////////////////////// -// Function: ShaderInput::Constructor -// Access: Published -// Description: -//////////////////////////////////////////////////////////////////// -INLINE ShaderInput:: -ShaderInput(CPT_InternalName name, const NodePath &np, int priority) : - _name(MOVE(name)), - _type(M_nodepath), - _priority(priority), - _stored_nodepath(np), - _bind_layer(0), - _bind_level(0), - _access(A_read) -{ -} - //////////////////////////////////////////////////////////////////// // Function: ShaderInput::Constructor // Access: Published @@ -678,16 +661,6 @@ get_texture() const { return DCAST(Texture, _value); } -//////////////////////////////////////////////////////////////////// -// Function: ShaderInput::get_nodepath -// Access: Published -// Description: -//////////////////////////////////////////////////////////////////// -INLINE const NodePath &ShaderInput:: -get_nodepath() const { - return _stored_nodepath; -} - //////////////////////////////////////////////////////////////////// // Function: ShaderInput::get_vector // Access: Published diff --git a/panda/src/pgraph/shaderInput.cxx b/panda/src/pgraph/shaderInput.cxx index a456d77900..8ab7ef3b1a 100644 --- a/panda/src/pgraph/shaderInput.cxx +++ b/panda/src/pgraph/shaderInput.cxx @@ -13,6 +13,7 @@ //////////////////////////////////////////////////////////////////// #include "shaderInput.h" +#include "paramNodePath.h" TypeHandle ShaderInput::_type_handle; @@ -32,13 +33,40 @@ get_blank() { return blank; } +//////////////////////////////////////////////////////////////////// +// Function: ShaderInput::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +ShaderInput:: +ShaderInput(CPT_InternalName name, const NodePath &np, int priority) : + _name(MOVE(name)), + _type(M_nodepath), + _priority(priority), + _value(new ParamNodePath(np)), + _bind_layer(0), + _bind_level(0), + _access(A_read) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderInput::get_nodepath +// Access: Published +// Description: Warning: no error checking is done. This *will* +// crash if get_value_type() is not M_nodepath. +//////////////////////////////////////////////////////////////////// +const NodePath &ShaderInput:: +get_nodepath() const { + return DCAST(ParamNodePath, _value)->get_value(); +} + //////////////////////////////////////////////////////////////////// // Function: ShaderInput::register_with_read_factory // Access: Public, Static -// Description: +// Description: //////////////////////////////////////////////////////////////////// void ShaderInput:: register_with_read_factory() { // IMPLEMENT ME } - diff --git a/panda/src/pgraph/shaderInput.h b/panda/src/pgraph/shaderInput.h index fed3aebe5c..26c7e2e375 100644 --- a/panda/src/pgraph/shaderInput.h +++ b/panda/src/pgraph/shaderInput.h @@ -19,7 +19,6 @@ #include "pandabase.h" #include "typedWritableReferenceCount.h" #include "pointerTo.h" -#include "nodePath.h" #include "internalName.h" #include "paramValue.h" #include "pta_float.h" @@ -53,7 +52,6 @@ PUBLISHED: static const ShaderInput *get_blank(); INLINE ShaderInput(CPT_InternalName name, int priority=0); - INLINE ShaderInput(CPT_InternalName name, const NodePath &np, int priority=0); INLINE ShaderInput(CPT_InternalName name, Texture *tex, int priority=0); INLINE ShaderInput(CPT_InternalName name, Texture *tex, const SamplerState &sampler, int priority=0); INLINE ShaderInput(CPT_InternalName name, Texture *tex, bool read, bool write, int z=-1, int n=0, int priority=0); @@ -90,6 +88,8 @@ PUBLISHED: INLINE ShaderInput(CPT_InternalName name, const LVecBase3i &vec, int priority=0); INLINE ShaderInput(CPT_InternalName name, const LVecBase2i &vec, int priority=0); + ShaderInput(CPT_InternalName name, const NodePath &np, int priority=0); + enum ShaderInputType { M_invalid = 0, M_texture, @@ -105,11 +105,12 @@ PUBLISHED: INLINE int get_value_type() const; INLINE int get_priority() const; INLINE Texture *get_texture() const; - INLINE const NodePath &get_nodepath() const; INLINE const LVecBase4 &get_vector() const; INLINE const Shader::ShaderPtrData &get_ptr() const; INLINE const SamplerState &get_sampler() const; + const NodePath &get_nodepath() const; + public: INLINE ParamValueBase *get_param() const; @@ -118,7 +119,6 @@ public: private: SamplerState _sampler; LVecBase4 _stored_vector; - NodePath _stored_nodepath; Shader::ShaderPtrData _stored_ptr; CPT_InternalName _name; PT(TypedWritableReferenceCount) _value; From 52fec094bcc2fa4a2b38b44e0d48d74673bafdf2 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 25 Feb 2015 16:24:56 +0100 Subject: [PATCH 20/32] Automatically coerce Python function to CallbackObject --- panda/src/putil/Sources.pp | 2 ++ panda/src/putil/callbackObject.h | 2 ++ panda/src/putil/callbackObject_ext.I | 32 +++++++++++++++++++ panda/src/putil/callbackObject_ext.h | 47 ++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 panda/src/putil/callbackObject_ext.I create mode 100644 panda/src/putil/callbackObject_ext.h diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index 7dc82eb5f4..8c72159364 100644 --- a/panda/src/putil/Sources.pp +++ b/panda/src/putil/Sources.pp @@ -27,6 +27,7 @@ cachedTypedWritableReferenceCount.h cachedTypedWritableReferenceCount.I \ callbackData.h callbackData.I \ callbackObject.h callbackObject.I \ + callbackObject_ext.h callbackObject_ext.I \ clockObject.h clockObject.I \ collideMask.h \ copyOnWriteObject.h copyOnWriteObject.I \ @@ -139,6 +140,7 @@ cachedTypedWritableReferenceCount.h cachedTypedWritableReferenceCount.I \ callbackData.h callbackData.I \ callbackObject.h callbackObject.I \ + callbackObject_ext.h callbackObject_ext.I \ clockObject.h clockObject.I \ collideMask.h \ copyOnWriteObject.h copyOnWriteObject.I \ diff --git a/panda/src/putil/callbackObject.h b/panda/src/putil/callbackObject.h index a8680e32fa..bb4f8f1223 100644 --- a/panda/src/putil/callbackObject.h +++ b/panda/src/putil/callbackObject.h @@ -38,6 +38,8 @@ public: PUBLISHED: virtual void output(ostream &out) const; + EXTENSION(static PT(CallbackObject) make(PyObject *function)); + public: virtual void do_callback(CallbackData *cbdata); diff --git a/panda/src/putil/callbackObject_ext.I b/panda/src/putil/callbackObject_ext.I new file mode 100644 index 0000000000..0bf73b2e01 --- /dev/null +++ b/panda/src/putil/callbackObject_ext.I @@ -0,0 +1,32 @@ +// Filename: callbackObject_ext.I +// Created by: rdb (25Feb15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: Extension::make +// Access: Published +// Description: This static constructor is merely provided so that +// interrogate can automatically coerce Python +// functions when passing them to a C++ function that +// accepts a CallbackObject. +//////////////////////////////////////////////////////////////////// +INLINE PT(CallbackObject) Extension:: +make(PyObject *function) { + if (function != Py_None && !PyCallable_Check(function)) { + PyErr_SetString(PyExc_TypeError, "expected callable or None"); + return NULL; + } else { + return new PythonCallbackObject(function); + } +} diff --git a/panda/src/putil/callbackObject_ext.h b/panda/src/putil/callbackObject_ext.h new file mode 100644 index 0000000000..1e0ceac72f --- /dev/null +++ b/panda/src/putil/callbackObject_ext.h @@ -0,0 +1,47 @@ +// Filename: callbackObject_ext.h +// Created by: rdb (25Feb15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef CALLBACKOBJECT_EXT_H +#define CALLBACKOBJECT_EXT_H + +#include "dtoolbase.h" + +#ifdef HAVE_PYTHON + +#include "extension.h" +#include "pythonCallbackObject.h" +#include "py_panda.h" + +//////////////////////////////////////////////////////////////////// +// Class : Extension +// Description : This class defines the extension methods for +// CallbackObject, which are called instead of +// any C++ methods with the same prototype. +// +// This just defines a static constructor, which makes +// it possible for Interrogate to automatically accept +// a Python function wherever a CallbackObject is +// accepted. +//////////////////////////////////////////////////////////////////// +template<> +class Extension : public ExtensionBase { +public: + INLINE static PT(CallbackObject) make(PyObject *function); +}; + +#include "callbackObject_ext.I" + +#endif // HAVE_PYTHON + +#endif // CALLBACKOBJECT_EXT_H From c3d1079b5aaf7abb397fee0543a499f27084bce8 Mon Sep 17 00:00:00 2001 From: Aaron Denney Date: Mon, 23 Feb 2015 12:24:32 -0800 Subject: [PATCH 21/32] Fix missing dependency making parallel builds unreliable. --- makepanda/makepanda.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index e61b24f756..72d30a5dab 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -4609,7 +4609,7 @@ if (PkgSkip("DIRECT")==0): OPTS=['DIR:direct/src/dcparser', 'WITHINPANDA', 'BUILDING:DIRECT', 'BISONPREFIX_dcyy'] CreateFile(GetOutputDir()+"/include/dcParser.h") TargetAdd('p3dcparser_dcParser.obj', opts=OPTS, input='dcParser.yxx') - TargetAdd('dcParser.h', input='p3egg_parser.obj', opts=['DEPENDENCYONLY']) + TargetAdd('dcParser.h', input='p3dcparser_dcParser.obj', opts=['DEPENDENCYONLY']) TargetAdd('p3dcparser_dcLexer.obj', opts=OPTS, input='dcLexer.lxx') TargetAdd('p3dcparser_composite1.obj', opts=OPTS, input='p3dcparser_composite1.cxx') TargetAdd('p3dcparser_composite2.obj', opts=OPTS, input='p3dcparser_composite2.cxx') From 72e1df987fcbf26d67049a1421b77eca6fe56f2b Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 25 Feb 2015 17:46:22 +0100 Subject: [PATCH 22/32] Fix pview issues with 1-frame animations and cycling between animations --- panda/src/framework/windowFramework.cxx | 44 ++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/panda/src/framework/windowFramework.cxx b/panda/src/framework/windowFramework.cxx index 57505bb0d3..becd06ee18 100644 --- a/panda/src/framework/windowFramework.cxx +++ b/panda/src/framework/windowFramework.cxx @@ -798,15 +798,28 @@ next_anim_control() { if (_anim_controls_enabled) { destroy_anim_controls(); + if (_anim_controls.get_num_anims() == 0) { + set_anim_controls(false); + return; + } + + // Stop the active animation. + pause_button(); ++_anim_index; + if (_anim_index >= _anim_controls.get_num_anims()) { set_anim_controls(false); + _anim_controls.loop_all(true); } else { create_anim_controls(); + play_button(); } } else { _anim_index = 0; set_anim_controls(true); + if (_anim_controls.get_num_anims() > 0) { + play_button(); + } } } @@ -1451,6 +1464,23 @@ create_anim_controls() { AnimControl *control = _anim_controls.get_anim(_anim_index); nassertv(control != (AnimControl *)NULL); + if (control->get_num_frames() <= 1) { + // Don't show the controls when the animation has only 0 or 1 frames. + ostringstream text; + text << _anim_controls.get_anim_name(_anim_index); + text << " (" << control->get_num_frames() << " frame" + << ((control->get_num_frames() == 1) ? "" : "s") << ")"; + + PT(TextNode) label = new TextNode("label"); + label->set_align(TextNode::A_center); + label->set_text(text.str()); + NodePath tnp = _anim_controls_group.attach_new_node(label); + tnp.set_pos(0.0f, 0.0f, 0.07f); + tnp.set_scale(0.1f); + + return; + } + PT(TextNode) label = new TextNode("anim_name"); label->set_align(TextNode::A_left); label->set_text(_anim_controls.get_anim_name(_anim_index)); @@ -1525,13 +1555,17 @@ update_anim_controls() { AnimControl *control = _anim_controls.get_anim(_anim_index); nassertv(control != (AnimControl *)NULL); - if (_anim_slider->is_button_down()) { - control->pose((int)(_anim_slider->get_value() + 0.5)); - } else { - _anim_slider->set_value((PN_stdfloat)control->get_frame()); + if (_anim_slider != NULL) { + if (_anim_slider->is_button_down()) { + control->pose((int)(_anim_slider->get_value() + 0.5)); + } else { + _anim_slider->set_value((PN_stdfloat)control->get_frame()); + } } - _frame_number->set_text(format_string(control->get_frame())); + if (_frame_number != NULL) { + _frame_number->set_text(format_string(control->get_frame())); + } control->set_play_rate(_play_rate_slider->get_value()); } From db87bc791451a1eaf1bbbcdf6471ce387707f6f5 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 27 Feb 2015 12:45:11 +0100 Subject: [PATCH 23/32] PointerToArray fixes, Windows build fixes, more move constructors --- dtool/src/dtoolutil/filename.I | 69 ++++++++++++++++++++ dtool/src/dtoolutil/filename.h | 12 +++- makepanda/makepandacore.py | 6 +- panda/src/express/datagram.I | 27 ++++++++ panda/src/express/datagram.h | 5 ++ panda/src/express/pointerToArray.I | 90 ++++++++++++++++++++++++++ panda/src/express/pointerToArray.h | 23 +++++++ panda/src/express/pointerToArrayBase.I | 36 +++++++---- panda/src/express/pointerToArrayBase.h | 4 ++ panda/src/express/pointerToArray_ext.I | 64 +++++++++++------- panda/src/express/pointerToArray_ext.h | 20 ++++++ panda/src/mathutil/pta_LMatrix3_ext.h | 28 ++++++++ panda/src/mathutil/pta_LMatrix4_ext.h | 28 ++++++++ panda/src/mathutil/pta_LVecBase2_ext.h | 30 +++++++++ panda/src/mathutil/pta_LVecBase3_ext.h | 30 +++++++++ panda/src/mathutil/pta_LVecBase4_ext.h | 30 +++++++++ panda/src/pgraph/nodePath.h | 2 + 17 files changed, 468 insertions(+), 36 deletions(-) create mode 100755 panda/src/mathutil/pta_LMatrix3_ext.h create mode 100755 panda/src/mathutil/pta_LMatrix4_ext.h create mode 100755 panda/src/mathutil/pta_LVecBase2_ext.h create mode 100755 panda/src/mathutil/pta_LVecBase3_ext.h create mode 100755 panda/src/mathutil/pta_LVecBase4_ext.h diff --git a/dtool/src/dtoolutil/filename.I b/dtool/src/dtoolutil/filename.I index 675eb5afc6..22c49f39bf 100644 --- a/dtool/src/dtoolutil/filename.I +++ b/dtool/src/dtoolutil/filename.I @@ -64,6 +64,39 @@ Filename(const Filename ©) : { } +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: Filename::Move Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE Filename:: +Filename(string &&filename) NOEXCEPT { + _flags = 0; + (*this) = move(filename); +} +#endif // USE_MOVE_SEMANTICS + +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: Filename::Move Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE Filename:: +Filename(Filename &&from) NOEXCEPT : + _filename(move(from._filename)), + _dirname_end(from._dirname_end), + _basename_start(from._basename_start), + _basename_end(from._basename_end), + _extension_start(from._extension_start), + _hash_start(from._hash_start), + _hash_end(from._hash_end), + _flags(from._flags) +{ +} +#endif // USE_MOVE_SEMANTICS + //////////////////////////////////////////////////////////////////// // Function: Filename::text_filename named constructor // Access: Published @@ -216,6 +249,42 @@ operator = (const Filename ©) { return *this; } +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: Filename::Move assignment operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE Filename &Filename:: +operator = (string &&filename) NOEXCEPT { + _filename = move(filename); + + locate_basename(); + locate_extension(); + locate_hash(); + return *this; +} +#endif // USE_MOVE_SEMANTICS + +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: Filename::Move assignment operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE Filename &Filename:: +operator = (Filename &&from) NOEXCEPT { + _filename = MOVE(from._filename); + _dirname_end = from._dirname_end; + _basename_start = from._basename_start; + _basename_end = from._basename_end; + _extension_start = from._extension_start; + _hash_start = from._hash_start; + _hash_end = from._hash_end; + _flags = from._flags; + return *this; +} +#endif // USE_MOVE_SEMANTICS //////////////////////////////////////////////////////////////////// // Function: Filename::string typecast operator diff --git a/dtool/src/dtoolutil/filename.h b/dtool/src/dtoolutil/filename.h index 493b912f69..45d975eac6 100644 --- a/dtool/src/dtoolutil/filename.h +++ b/dtool/src/dtoolutil/filename.h @@ -68,6 +68,11 @@ PUBLISHED: Filename(const Filename &dirname, const Filename &basename); INLINE ~Filename(); +#ifdef USE_MOVE_SEMANTICS + INLINE Filename(string &&filename) NOEXCEPT; + INLINE Filename(Filename &&from) NOEXCEPT; +#endif + #ifdef HAVE_PYTHON PyObject *__reduce__(PyObject *self) const; #endif @@ -88,7 +93,7 @@ PUBLISHED: Type type = T_general); static Filename from_os_specific_w(const wstring &os_specific, Type type = T_general); - static Filename expand_from(const string &user_string, + static Filename expand_from(const string &user_string, Type type = T_general); static Filename temporary(const string &dirname, const string &prefix, const string &suffix = string(), @@ -105,6 +110,11 @@ PUBLISHED: INLINE Filename &operator = (const char *filename); INLINE Filename &operator = (const Filename ©); +#ifdef USE_MOVE_SEMANTICS + INLINE Filename &operator = (string &&filename) NOEXCEPT; + INLINE Filename &operator = (Filename &&from) NOEXCEPT; +#endif + // And retrieval is by any of the classic string operations. INLINE operator const string & () const; INLINE const char *c_str() const; diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 138c372af3..9097948e98 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -210,6 +210,8 @@ def PrettyTime(t): return "%d sec" % (seconds) def ProgressOutput(progress, msg, target = None): + sys.stdout.flush() + sys.stderr.flush() prefix = "" thisthread = threading.currentThread() if thisthread is MAINTHREAD: @@ -235,6 +237,8 @@ def ProgressOutput(progress, msg, target = None): suffix = GetColor() print(''.join((prefix, msg, suffix))) + sys.stdout.flush() + sys.stderr.flush() def exit(msg = ""): sys.stdout.flush() @@ -498,7 +502,7 @@ def oscmd(cmd, ignoreError = False): print(GetColor("blue") + cmd.split(" ", 1)[0] + " " + GetColor("magenta") + cmd.split(" ", 1)[1] + GetColor()) sys.stdout.flush() - if sys.platform == "win32": + if sys.platform in ("win32", "cygwin"): exe = cmd.split()[0] exe_path = LocateBinary(exe) if exe_path is None: diff --git a/panda/src/express/datagram.I b/panda/src/express/datagram.I index 28c633a5c8..123d428b1b 100644 --- a/panda/src/express/datagram.I +++ b/panda/src/express/datagram.I @@ -82,6 +82,33 @@ operator = (const Datagram ©) { _stdfloat_double = copy._stdfloat_double; } +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: Datagram::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE Datagram:: +Datagram(Datagram &&from) NOEXCEPT : + _data(move(from._data)), + _stdfloat_double(from._stdfloat_double) +{ +} +#endif // USE_MOVE_SEMANTICS + +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: Datagram::Move Assignment Operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void Datagram:: +operator = (Datagram &&from) NOEXCEPT { + _data = move(from._data); + _stdfloat_double = from._stdfloat_double; +} +#endif // USE_MOVE_SEMANTICS + //////////////////////////////////////////////////////////////////// // Function: Datagram::add_bool // Access: Public diff --git a/panda/src/express/datagram.h b/panda/src/express/datagram.h index 71d44a018b..5de3ce6467 100644 --- a/panda/src/express/datagram.h +++ b/panda/src/express/datagram.h @@ -48,6 +48,11 @@ PUBLISHED: INLINE Datagram(const Datagram ©); INLINE void operator = (const Datagram ©); +#ifdef USE_MOVE_SEMANTICS + INLINE Datagram(Datagram &&from) NOEXCEPT; + INLINE void operator = (Datagram &&from) NOEXCEPT; +#endif + virtual ~Datagram(); virtual void clear(); diff --git a/panda/src/express/pointerToArray.I b/panda/src/express/pointerToArray.I index c833954570..dbb5f9a0bf 100644 --- a/panda/src/express/pointerToArray.I +++ b/panda/src/express/pointerToArray.I @@ -77,6 +77,21 @@ PointerToArray(const PointerToArray ©) : { } +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: PointerToArray::Move Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE PointerToArray:: +PointerToArray(PointerToArray &&from) NOEXCEPT : + PointerToArrayBase(move(from)), + _type_handle(from._type_handle) +{ +} +#endif // USE_MOVE_SEMANTICS + //////////////////////////////////////////////////////////////////// // Function: PointerToArray::begin // Access: Public @@ -682,6 +697,21 @@ operator = (const PointerToArray ©) { return *this; } +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: PointerToArray::Assignment operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE PointerToArray &PointerToArray:: +operator = (PointerToArray &&from) NOEXCEPT { + _type_handle = from._type_handle; + ((PointerToArray *)this)->reassign(move(from)); + return *this; +} +#endif // USE_MOVE_SEMANTICS + //////////////////////////////////////////////////////////////////// // Function: PointerToArray::clear // Access: Public @@ -736,6 +766,36 @@ ConstPointerToArray(const ConstPointerToArray ©) : { } +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: ConstPointerToArray::Move Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ConstPointerToArray:: +ConstPointerToArray(PointerToArray &&from) NOEXCEPT : + PointerToArrayBase(move(from)), + _type_handle(from._type_handle) +{ +} +#endif // USE_MOVE_SEMANTICS + +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: ConstPointerToArray::Move Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ConstPointerToArray:: +ConstPointerToArray(ConstPointerToArray &&from) NOEXCEPT : + PointerToArrayBase(move(from)), + _type_handle(from._type_handle) +{ +} +#endif // USE_MOVE_SEMANTICS + //////////////////////////////////////////////////////////////////// // Function: ConstPointerToArray::begin // Access: Public @@ -1141,6 +1201,36 @@ operator = (const ConstPointerToArray ©) { return *this; } +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: ConstPointerToArray::Assignment operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ConstPointerToArray &ConstPointerToArray:: +operator = (PointerToArray &&from) NOEXCEPT { + _type_handle = from._type_handle; + ((ConstPointerToArray *)this)->reassign(move(from)); + return *this; +} +#endif // USE_MOVE_SEMANTICS + +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: ConstPointerToArray::Assignment operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ConstPointerToArray &ConstPointerToArray:: +operator = (ConstPointerToArray &&from) NOEXCEPT { + _type_handle = from._type_handle; + ((ConstPointerToArray *)this)->reassign(move(from)); + return *this; +} +#endif // USE_MOVE_SEMANTICS + //////////////////////////////////////////////////////////////////// // Function: ConstPointerToArray::clear // Access: Public diff --git a/panda/src/express/pointerToArray.h b/panda/src/express/pointerToArray.h index 78b504d202..0f1d4cd5c8 100644 --- a/panda/src/express/pointerToArray.h +++ b/panda/src/express/pointerToArray.h @@ -151,6 +151,10 @@ public: INLINE PointerToArray(size_type n, const Element &value, TypeHandle type_handle = get_type_handle(Element)); INLINE PointerToArray(const PointerToArray ©); +#ifdef USE_MOVE_SEMANTICS + INLINE PointerToArray(PointerToArray &&from) NOEXCEPT; +#endif + public: // Duplicating the interface of vector. The following member // functions are all const, because they do not reassign the @@ -231,6 +235,12 @@ public: operator = (ReferenceCountedVector *ptr); INLINE PointerToArray & operator = (const PointerToArray ©); + +#ifdef USE_MOVE_SEMANTICS + INLINE PointerToArray & + operator = (PointerToArray &&from) NOEXCEPT; +#endif + INLINE void clear(); private: @@ -305,6 +315,11 @@ PUBLISHED: INLINE ConstPointerToArray(const PointerToArray ©); INLINE ConstPointerToArray(const ConstPointerToArray ©); +#ifdef USE_MOVE_SEMANTICS + INLINE ConstPointerToArray(PointerToArray &&from) NOEXCEPT; + INLINE ConstPointerToArray(ConstPointerToArray &&from) NOEXCEPT; +#endif + // Duplicating the interface of vector. INLINE iterator begin() const; @@ -355,6 +370,14 @@ PUBLISHED: operator = (const PointerToArray ©); INLINE ConstPointerToArray & operator = (const ConstPointerToArray ©); + +#ifdef USE_MOVE_SEMANTICS + INLINE ConstPointerToArray & + operator = (PointerToArray &&from) NOEXCEPT; + INLINE ConstPointerToArray & + operator = (ConstPointerToArray &&from) NOEXCEPT; +#endif + INLINE void clear(); private: diff --git a/panda/src/express/pointerToArrayBase.I b/panda/src/express/pointerToArrayBase.I index f8f5e91769..343fb7374d 100644 --- a/panda/src/express/pointerToArrayBase.I +++ b/panda/src/express/pointerToArrayBase.I @@ -57,11 +57,11 @@ template INLINE ReferenceCountedVector:: ~ReferenceCountedVector() { } - + //////////////////////////////////////////////////////////////////// // Function: ReferenceCountedVector::size // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// template INLINE TYPENAME ReferenceCountedVector::size_type ReferenceCountedVector:: @@ -72,7 +72,7 @@ size() const { //////////////////////////////////////////////////////////////////// // Function: ReferenceCountedVector::insert // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// template INLINE TYPENAME ReferenceCountedVector::iterator ReferenceCountedVector:: @@ -83,7 +83,7 @@ insert(iterator position, const Element &x) { //////////////////////////////////////////////////////////////////// // Function: ReferenceCountedVector::insert // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// template INLINE void ReferenceCountedVector:: @@ -94,7 +94,7 @@ insert(iterator position, size_type n, const Element &x) { //////////////////////////////////////////////////////////////////// // Function: ReferenceCountedVector::erase // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// template INLINE void ReferenceCountedVector:: @@ -105,7 +105,7 @@ erase(iterator position) { //////////////////////////////////////////////////////////////////// // Function: ReferenceCountedVector::erase // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// template INLINE void ReferenceCountedVector:: @@ -116,7 +116,7 @@ erase(iterator first, iterator last) { //////////////////////////////////////////////////////////////////// // Function: ReferenceCountedVector::pop_back // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// template INLINE void ReferenceCountedVector:: @@ -127,7 +127,7 @@ pop_back() { //////////////////////////////////////////////////////////////////// // Function: ReferenceCountedVector::clear // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// template INLINE void ReferenceCountedVector:: @@ -138,7 +138,7 @@ clear() { //////////////////////////////////////////////////////////////////// // Function: PointerToArrayBase::Constructor // Access: Protected -// Description: +// Description: //////////////////////////////////////////////////////////////////// template INLINE PointerToArrayBase:: @@ -150,7 +150,7 @@ PointerToArrayBase(ReferenceCountedVector *ptr) : //////////////////////////////////////////////////////////////////// // Function: PointerToArrayBase::Copy Constructor // Access: Protected -// Description: +// Description: //////////////////////////////////////////////////////////////////// template INLINE PointerToArrayBase:: @@ -159,10 +159,24 @@ PointerToArrayBase(const PointerToArrayBase ©) : { } +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: PointerToArrayBase::Move Constructor +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE PointerToArrayBase:: +PointerToArrayBase(PointerToArrayBase &&from) NOEXCEPT : + PointerToBase >(move(from)) +{ +} +#endif // USE_MOVE_SEMANTICS + //////////////////////////////////////////////////////////////////// // Function: PointerToArrayBase::Destructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// template INLINE PointerToArrayBase:: diff --git a/panda/src/express/pointerToArrayBase.h b/panda/src/express/pointerToArrayBase.h index c660a3b0f2..fe481842be 100644 --- a/panda/src/express/pointerToArrayBase.h +++ b/panda/src/express/pointerToArrayBase.h @@ -82,6 +82,10 @@ protected: INLINE PointerToArrayBase(ReferenceCountedVector *ptr); INLINE PointerToArrayBase(const PointerToArrayBase ©); +#ifdef USE_MOVE_SEMANTICS + INLINE PointerToArrayBase(PointerToArrayBase &&from) NOEXCEPT; +#endif + PUBLISHED: INLINE ~PointerToArrayBase(); }; diff --git a/panda/src/express/pointerToArray_ext.I b/panda/src/express/pointerToArray_ext.I index c53b0c3ee0..f8a1ffc600 100644 --- a/panda/src/express/pointerToArray_ext.I +++ b/panda/src/express/pointerToArray_ext.I @@ -22,26 +22,33 @@ // Python buffer protocol. //////////////////////////////////////////////////////////////////// template -void Extension >:: +INLINE void Extension >:: __init__(PyObject *self, PyObject *source) { #if PY_VERSION_HEX >= 0x02060000 if (PyObject_CheckBuffer(source)) { // User passed a buffer object. Py_buffer view; if (PyObject_GetBuffer(source, &view, PyBUF_CONTIG_RO) == -1) { - PyErr_SetString(PyExc_TypeError, "PointerToArray constructor requires a contiguous buffer"); + PyErr_SetString(PyExc_TypeError, + "PointerToArray constructor requires a contiguous buffer"); return; } if (view.itemsize != 1 && view.itemsize != sizeof(Element)) { - PyErr_SetString(PyExc_TypeError, "buffer.itemsize does not match PointerToArray element size"); + PyErr_SetString(PyExc_TypeError, + "buffer.itemsize does not match PointerToArray element size"); return; } - int num_elements = view.len / sizeof(Element); - this->_this->insert(this->_this->begin(), num_elements, Element()); + if (view.len % sizeof(Element) != 0) { + PyErr_Format(PyExc_ValueError, + "byte buffer is not a multiple of %zu bytes", + sizeof(Element)); + return; + } if (view.len > 0) { + this->_this->resize(view.len / sizeof(Element)); memcpy(this->_this->p(), view.buf, view.len); } @@ -52,21 +59,22 @@ __init__(PyObject *self, PyObject *source) { if (!PySequence_Check(source)) { // If passed with a non-sequence, this isn't the right constructor. - PyErr_SetString(PyExc_TypeError, "PointerToArray constructor requires a sequence or buffer object"); + PyErr_SetString(PyExc_TypeError, + "PointerToArray constructor requires a sequence or buffer object"); return; } // If we were passed a Python string, then instead of storing it // character-at-a-time, just load the whole string as a data - // buffer. + // buffer. Not sure if this case is still necessary - don't Python + // str/bytes objects export the buffer protocol, as above? #if PY_MAJOR_VERSION >= 3 if (PyBytes_Check(source)) { int size = PyBytes_Size(source); if (size % sizeof(Element) != 0) { - ostringstream stream; - stream << "Buffer not a multiple of " << sizeof(Element) << " bytes"; - string str = stream.str(); - PyErr_SetString(PyExc_ValueError, str.c_str()); + PyErr_Format(PyExc_ValueError, + "bytes object is not a multiple of %zu bytes", + sizeof(Element)); return; } @@ -85,10 +93,9 @@ __init__(PyObject *self, PyObject *source) { if (PyString_CheckExact(source)) { int size = PyString_Size(source); if (size % sizeof(Element) != 0) { - ostringstream stream; - stream << "Buffer not a multiple of " << sizeof(Element) << " bytes"; - string str = stream.str(); - PyErr_SetString(PyExc_ValueError, str.c_str()); + PyErr_Format(PyExc_ValueError, + "str object is not a multiple of %zu bytes", + sizeof(Element)); return; } @@ -107,20 +114,29 @@ __init__(PyObject *self, PyObject *source) { // Now construct the internal list by copying the elements // one-at-a-time from Python. + PyObject *push_back = PyObject_GetAttrString(self, "push_back"); + if (push_back == NULL) { + PyErr_BadArgument(); + return; + } + + // We need to initialize the this pointer before we can call push_back. + ((Dtool_PyInstDef *)self)->_ptr_to_object = (void *)this->_this; + int size = PySequence_Size(source); for (int i = 0; i < size; ++i) { PyObject *item = PySequence_GetItem(source, i); if (item == NULL) { return; } - PyObject *result = PyObject_CallMethod(self, (char *)"push_back", (char *)"O", item); + PyObject *result = PyObject_CallFunctionObjArgs(push_back, item, NULL); Py_DECREF(item); if (result == NULL) { // Unable to add item--probably it wasn't of the appropriate type. - ostringstream stream; - stream << "Element " << i << " in sequence passed to PointerToArray constructor could not be added"; - string str = stream.str(); - PyErr_SetString(PyExc_TypeError, str.c_str()); + PyErr_Print(); + PyErr_Format(PyExc_TypeError, + "Element %d in sequence passed to PointerToArray " + "constructor could not be added", i); return; } Py_DECREF(result); @@ -161,7 +177,9 @@ __setitem__(size_t n, const Element &value) { template INLINE void Extension >:: __init__(PyObject *self, PyObject *source) { - new (this->_this) ConstPointerToArray(get_type_handle(Element)); + PointerToArray array; + invoke_extension(&array).__init__(self, source); + *(this->_this) = MOVE(array); } //////////////////////////////////////////////////////////////////// @@ -240,7 +258,7 @@ __releasebuffer__(PyObject *self, Py_buffer *view) const { if (view->internal != NULL) { // Oh, right, let's not forget to unref this. - ((const PointerToArray *) view->internal)->unref(); + unref_delete((const PointerToArray *)view->internal); view->internal = NULL; } } @@ -314,7 +332,7 @@ __releasebuffer__(PyObject *self, Py_buffer *view) const { if (view->internal != NULL) { // Oh, right, let's not forget to unref this. - ((const PointerToArray *) view->internal)->unref(); + unref_delete((const PointerToArray *)view->internal); view->internal = NULL; } } diff --git a/panda/src/express/pointerToArray_ext.h b/panda/src/express/pointerToArray_ext.h index b403ed4dc6..c4f7afdfec 100644 --- a/panda/src/express/pointerToArray_ext.h +++ b/panda/src/express/pointerToArray_ext.h @@ -66,6 +66,26 @@ public: #endif }; +#ifdef _MSC_VER +// Ugh... MSVC needs this because they still don't have a decent linker. +#include "PTA_uchar.h" +#include "PTA_ushort.h" +#include "PTA_float.h" +#include "PTA_double.h" +#include "PTA_int.h" + +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +#endif + // This macro is used to map a data type to a format code // as used in the Python 'struct' and 'array' modules. #define get_format_code(type) _get_format_code((const type *)0) diff --git a/panda/src/mathutil/pta_LMatrix3_ext.h b/panda/src/mathutil/pta_LMatrix3_ext.h new file mode 100755 index 0000000000..4cda107aef --- /dev/null +++ b/panda/src/mathutil/pta_LMatrix3_ext.h @@ -0,0 +1,28 @@ +// Filename: pta_LMatrix3_ext.h +// Created by: rdb (25Feb15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef PTA_LMATRIX3_EXT_H +#define PTA_LMATRIX3_EXT_H + +#include "pointerToArray_ext.h" +#include "pta_LMatrix3.h" + +#if defined(_MSC_VER) && !defined(CPPPARSER) +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +#endif + +#endif diff --git a/panda/src/mathutil/pta_LMatrix4_ext.h b/panda/src/mathutil/pta_LMatrix4_ext.h new file mode 100755 index 0000000000..02a1e86dd8 --- /dev/null +++ b/panda/src/mathutil/pta_LMatrix4_ext.h @@ -0,0 +1,28 @@ +// Filename: pta_LMatrix4_ext.h +// Created by: rdb (25Feb15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef PTA_LMATRIX4_EXT_H +#define PTA_LMATRIX4_EXT_H + +#include "pointerToArray_ext.h" +#include "pta_LMatrix4.h" + +#if defined(_MSC_VER) && !defined(CPPPARSER) +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +#endif + +#endif diff --git a/panda/src/mathutil/pta_LVecBase2_ext.h b/panda/src/mathutil/pta_LVecBase2_ext.h new file mode 100755 index 0000000000..4624ec604f --- /dev/null +++ b/panda/src/mathutil/pta_LVecBase2_ext.h @@ -0,0 +1,30 @@ +// Filename: pta_LVecBase2_ext.h +// Created by: rdb (25Feb15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef PTA_LVECBASE2_EXT_H +#define PTA_LVECBASE2_EXT_H + +#include "pointerToArray_ext.h" +#include "pta_LVecBase2.h" + +#if defined(_MSC_VER) && !defined(CPPPARSER) +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +#endif + +#endif diff --git a/panda/src/mathutil/pta_LVecBase3_ext.h b/panda/src/mathutil/pta_LVecBase3_ext.h new file mode 100755 index 0000000000..2ae87f518f --- /dev/null +++ b/panda/src/mathutil/pta_LVecBase3_ext.h @@ -0,0 +1,30 @@ +// Filename: pta_LVecBase3_ext.h +// Created by: rdb (25Feb15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef PTA_LVECBASE3_EXT_H +#define PTA_LVECBASE3_EXT_H + +#include "pointerToArray_ext.h" +#include "pta_LVecBase3.h" + +#if defined(_MSC_VER) && !defined(CPPPARSER) +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +#endif + +#endif diff --git a/panda/src/mathutil/pta_LVecBase4_ext.h b/panda/src/mathutil/pta_LVecBase4_ext.h new file mode 100755 index 0000000000..29eee6530a --- /dev/null +++ b/panda/src/mathutil/pta_LVecBase4_ext.h @@ -0,0 +1,30 @@ +// Filename: pta_LVecBase4_ext.h +// Created by: rdb (25Feb15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef PTA_LVECBASE4_EXT_H +#define PTA_LVECBASE4_EXT_H + +#include "pointerToArray_ext.h" +#include "pta_LVecBase4.h" + +#if defined(_MSC_VER) && !defined(CPPPARSER) +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +template class EXPORT_THIS Extension; +#endif + +#endif diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index d84519547d..8163e78767 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -39,6 +39,8 @@ #include "pta_LVecBase2.h" #include "stl_compares.h" #include "shaderInput.h" +#include "textureCollection.h" +#include "textureStageCollection.h" class NodePathCollection; class FindApproxPath; From 413162110b5518ea8f1c855597b4f66d39d734eb Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 27 Feb 2015 14:18:17 +0100 Subject: [PATCH 24/32] Fix FCollada compile issues on Windows --- pandatool/src/daeegg/daeCharacter.cxx | 2 +- pandatool/src/daeegg/daeCharacter.h | 2 +- pandatool/src/daeegg/daeToEggConverter.cxx | 2 +- pandatool/src/daeegg/pre_fcollada_include.h | 7 +++++++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/pandatool/src/daeegg/daeCharacter.cxx b/pandatool/src/daeegg/daeCharacter.cxx index d3c091d7bf..aea226b9b6 100644 --- a/pandatool/src/daeegg/daeCharacter.cxx +++ b/pandatool/src/daeegg/daeCharacter.cxx @@ -320,7 +320,7 @@ build_table(EggTable *parent, FCDSceneNode* node, const pset &keys) { } // Quantize the FPS, otherwise Panda complains about FPS mismatches. - float fps = round(((keys.size() - 1) / timing_total) * 100) * 0.01f; + float fps = cfloor(((keys.size() - 1) / timing_total) * 100 + 0.5f) * 0.01f; xform->set_fps(fps); // Loop through the children joints diff --git a/pandatool/src/daeegg/daeCharacter.h b/pandatool/src/daeegg/daeCharacter.h index cd656eae06..4b9e86af73 100644 --- a/pandatool/src/daeegg/daeCharacter.h +++ b/pandatool/src/daeegg/daeCharacter.h @@ -45,7 +45,7 @@ public: _bind_pose(LMatrix4d::ident_mat()) {} LMatrix4d _bind_pose; - const PT(EggGroup) _group; + PT(EggGroup) _group; const FCDSceneNode *_scene_node; DaeCharacter *_character; }; diff --git a/pandatool/src/daeegg/daeToEggConverter.cxx b/pandatool/src/daeegg/daeToEggConverter.cxx index 8ff46b401b..88ae0c7027 100755 --- a/pandatool/src/daeegg/daeToEggConverter.cxx +++ b/pandatool/src/daeegg/daeToEggConverter.cxx @@ -228,7 +228,7 @@ convert_file(const Filename &filename) { Characters::iterator it; DaeCharacter *character; for (it = _characters.begin(); it != _characters.end(); ++it) { - DaeCharacter *character = *it; + character = *it; // Collect key frame timings. if (get_animation_convert() == AC_both || diff --git a/pandatool/src/daeegg/pre_fcollada_include.h b/pandatool/src/daeegg/pre_fcollada_include.h index a2497f5140..70c80ca324 100755 --- a/pandatool/src/daeegg/pre_fcollada_include.h +++ b/pandatool/src/daeegg/pre_fcollada_include.h @@ -22,6 +22,13 @@ #error You must include pre_fcollada_include.h before including FCollada.h! #endif +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include +#endif + // FCollada expects LINUX to be defined on linux #ifdef IS_LINUX #ifndef LINUX From 3d9d9bfc95e41ee6a8905ecf04479c5573c7f046 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 27 Feb 2015 19:59:54 +0100 Subject: [PATCH 25/32] Deprecate use of without specifying "descend" flag --- panda/src/doc/eggSyntax.txt | 11 ++++++++--- panda/src/egg2pg/eggLoader.cxx | 4 ++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/panda/src/doc/eggSyntax.txt b/panda/src/doc/eggSyntax.txt index 7cbf1b228f..4b57d91192 100644 --- a/panda/src/doc/eggSyntax.txt +++ b/panda/src/doc/eggSyntax.txt @@ -1476,6 +1476,10 @@ GROUPING ENTRIES its geometry is used to define the extent of the collision surface (unless the "descend" flag is given; see below). + It is now deprecated to use without "descend"; it will + become the default soon. You should always specify it for best + compatibility. + Valid types so far are: Plane @@ -1538,11 +1542,12 @@ GROUPING ENTRIES descend - Instead of creating only one collision object of the given type, - each group descended from this node that contains geometry will + Each group descended from this node that contains geometry will define a new collision object of the given type. The event name, if any, will also be inherited from the top node and - shared among all the collision objects. + shared among all the collision objects. This option will soon + be the default; it is suggested that it is always specified for + most compatibility. keep diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index ae3be83199..40ca88b6e7 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -2970,6 +2970,10 @@ make_collision_solids(EggGroup *start_group, EggGroup *egg_group, make_collision_solids(start_group, DCAST(EggGroup, *ci), cnode); } } + } else { + egg2pg_cat.warning() + << "Using without 'descend' is deprecated. 'descend' " + << "will become the default in a future version of Panda3D.\n"; } } From 223620e27ea0d6227d800a2417388de098b6b97f Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 28 Feb 2015 13:03:45 +0100 Subject: [PATCH 26/32] Fix draw mask propagation for initially hidden nodes when when frustum culling is off --- panda/src/pgraph/pandaNode.I | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/panda/src/pgraph/pandaNode.I b/panda/src/pgraph/pandaNode.I index 162f08e03b..3a1f0c86de 100644 --- a/panda/src/pgraph/pandaNode.I +++ b/panda/src/pgraph/pandaNode.I @@ -721,13 +721,15 @@ get_user_bounds(int pipeline_stage, Thread *current_thread) const { //////////////////////////////////////////////////////////////////// INLINE void PandaNode:: mark_bounds_stale(int pipeline_stage, Thread *current_thread) const { - // It's important that we don't hold the lock during the call to - // force_bounds_stale(). + // We check whether it is already marked stale. If so, we don't have + // to make the call to force_bounds_stale(). bool is_stale_bounds; { CDStageReader cdata(_cycler, pipeline_stage, current_thread); - is_stale_bounds = (cdata->_last_bounds_update != cdata->_next_update); + is_stale_bounds = (cdata->_last_update != cdata->_next_update); } + // It's important that we don't hold the lock during the call to + // force_bounds_stale(). if (!is_stale_bounds) { ((PandaNode *)this)->force_bounds_stale(pipeline_stage, current_thread); } @@ -1833,7 +1835,7 @@ get_off_clip_planes() const { //////////////////////////////////////////////////////////////////// INLINE CPT(BoundingVolume) PandaNodePipelineReader:: get_bounds() const { - nassertr(_cdata->_last_update == _cdata->_next_update, _cdata->_external_bounds); + nassertr(_cdata->_last_bounds_update == _cdata->_next_update, _cdata->_external_bounds); return _cdata->_external_bounds; } @@ -1852,7 +1854,7 @@ get_bounds() const { //////////////////////////////////////////////////////////////////// INLINE int PandaNodePipelineReader:: get_nested_vertices() const { - nassertr(_cdata->_last_update == _cdata->_next_update, _cdata->_nested_vertices); + nassertr(_cdata->_last_bounds_update == _cdata->_next_update, _cdata->_nested_vertices); return _cdata->_nested_vertices; } From 2e555db30e1eb215e1ecf605975220b0e6e31abc Mon Sep 17 00:00:00 2001 From: alan eborn Date: Wed, 15 Oct 2014 15:06:25 +0000 Subject: [PATCH 27/32] DirectDialog--removal of model-loading by default and a bug-fix Signed-off-by: rdb --- direct/src/gui/DirectDialog.py | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/direct/src/gui/DirectDialog.py b/direct/src/gui/DirectDialog.py index 803cce5467..44cb182ab0 100644 --- a/direct/src/gui/DirectDialog.py +++ b/direct/src/gui/DirectDialog.py @@ -94,8 +94,9 @@ class DirectDialog(DirectFrame): ('text', '', None), ('text_align', TextNode.ALeft, None), ('text_scale', 0.06, None), - ('image', DGG.getDefaultDialogGeom(), None), - ('relief', None, None), + ('image', None, None), + ('relief', DGG.RAISED, None), + ('borderWidth', (0.01, 0.01), None), ('buttonTextList', [], DGG.INITOPT), ('buttonGeomList', [], DGG.INITOPT), ('buttonImageList', [], DGG.INITOPT), @@ -210,10 +211,16 @@ class DirectDialog(DirectFrame): bounds = self.stateNodePath[0].getTightBounds() if image: image.reparentTo(self.stateNodePath[0]) - l = bounds[0][0] - r = bounds[1][0] - b = bounds[0][2] - t = bounds[1][2] + if bounds is None: + l = 0 + r = 0 + b = 0 + t = 0 + else: + l = bounds[0][0] + r = bounds[1][0] + b = bounds[0][2] + t = bounds[1][2] # Center text and geom around origin # How far is center of text from origin? xOffset = -(l+r)*0.5 @@ -246,10 +253,16 @@ class DirectDialog(DirectFrame): bl = br = bb = bt = 0 for button in self.buttonList: bounds = button.stateNodePath[0].getTightBounds() - bl = min(bl, bounds[0][0]) - br = max(br, bounds[1][0]) - bb = min(bb, bounds[0][2]) - bt = max(bt, bounds[1][2]) + if bounds is None: + bl = 0 + br = 0 + bb = 0 + bt = 0 + else: + bl = min(bl, bounds[0][0]) + br = max(br, bounds[1][0]) + bb = min(bb, bounds[0][2]) + bt = max(bt, bounds[1][2]) bl -= bpad[0] br += bpad[0] bb -= bpad[1] @@ -303,6 +316,7 @@ class DirectDialog(DirectFrame): # reduce bottom by pad, button height and 2*button pad b = min(b - self['midPad'] - bpad[1] - bHeight - bpad[1], b) - pad[1] t = t + self['topPad'] + pad[1] + self['frameSize'] = (l, r, b, t) self['image_scale'] = (r - l, 1, t - b) # Center frame about text and buttons self['image_pos'] = ((l+r)*0.5, 0.0, (b+t)*0.5) From 178c16e94b0c26d93f7b62ab161d87959ad4ca9f Mon Sep 17 00:00:00 2001 From: alan eborn Date: Wed, 15 Oct 2014 15:05:26 +0000 Subject: [PATCH 28/32] DirectRadioButton--removal of model-loading by default and indicator handling Signed-off-by: rdb --- direct/src/gui/DirectRadioButton.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/direct/src/gui/DirectRadioButton.py b/direct/src/gui/DirectRadioButton.py index c96ba13dbb..c2cb423f0d 100755 --- a/direct/src/gui/DirectRadioButton.py +++ b/direct/src/gui/DirectRadioButton.py @@ -43,7 +43,7 @@ class DirectRadioButton(DirectButton): ('boxGeom', None, None), ('boxGeomColor', None, None), ('boxGeomScale', 1.0, None), - ('boxImage', loader.loadModel('models/gui/radio_button_gui'), None), + ('boxImage', None, None), ('boxImageScale', 1.0, None), ('boxImageColor', VBase4(1, 1, 1, 1), None), ('boxRelief', None, None), @@ -69,9 +69,11 @@ class DirectRadioButton(DirectButton): # Call option initialization functions self.initialiseoptions(DirectRadioButton) # After initialization with X giving it the correct size, put back space - if self['boxGeom'] == None: + if self['boxGeom'] is None: + if not 'boxRelief' in kw and self['boxImage'] is None: + self.indicator['relief'] = DGG.SUNKEN self.indicator['text'] = (' ', '*') - self.indicator['text_pos'] = (0, -.5) + self.indicator['text_pos'] = (0, -.25) else: self.indicator['text'] = (' ', ' ') From e33cac03fe59a11d7578cd15c1a3599f4003db0f Mon Sep 17 00:00:00 2001 From: alan eborn Date: Wed, 15 Oct 2014 15:07:29 +0000 Subject: [PATCH 29/32] Transitions--changes to fade screen Signed-off-by: rdb --- direct/src/showbase/Transitions.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/direct/src/showbase/Transitions.py b/direct/src/showbase/Transitions.py index 7e3103a0d0..ca4919a48f 100644 --- a/direct/src/showbase/Transitions.py +++ b/direct/src/showbase/Transitions.py @@ -59,15 +59,12 @@ class Transitions: # Reload fade if its already been created if self.fade: - del self.fade + self.fade.destroy() self.fade = None self.loadFade() def loadFade(self): - if not self.fadeModel: - self.fadeModel = loader.loadModel(self.FadeModelName) - - if self.fade == None: + if self.fade is None: # We create a DirectFrame for the fade polygon, instead of # simply loading the polygon model and using it directly, # so that it will also obscure mouse events for objects @@ -80,10 +77,15 @@ class Transitions: image_scale = (4, 2, 2), state = DGG.NORMAL, ) + if not self.fadeModel: + # No fade model was given, so we make this the fade model. + self.fade["relief"] = DGG.FLAT + self.fade["frameSize"] = (-2, 2, -1, 1) + self.fade["frameColor"] = (0, 0, 0, 1) + self.fade.setTransparency(TransparencyAttrib.MAlpha) self.fade.setBin('unsorted', 0) self.fade.setColor(0,0,0,0) - def getFadeInIval(self, t=0.5, finishIval=None): """ Returns an interval without starting it. This is particularly useful in From 04d4309b14515ee7f0bbd23360a61c1ee02a795a Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 1 Mar 2015 11:46:52 +0100 Subject: [PATCH 30/32] SSE2-enhanced sRGB encode (with runtime CPU detection) --- .../interfaceMakerPythonNative.cxx | 9 +- makepanda/makepanda.py | 12 +- panda/src/gobj/texture.cxx | 141 +++++++------- panda/src/gobj/texture.h | 7 + panda/src/pnmimage/convert_srgb.I | 175 ++++++++++++++++++ panda/src/pnmimage/convert_srgb.cxx | 165 +++++++++++++++++ panda/src/pnmimage/convert_srgb.h | 59 ++++++ panda/src/pnmimage/convert_srgb_sse2.cxx | 151 +++++++++++++++ panda/src/pnmimage/p3pnmimage_composite1.cxx | 1 + panda/src/tinydisplay/zbuffer.h | 2 +- 10 files changed, 645 insertions(+), 77 deletions(-) create mode 100644 panda/src/pnmimage/convert_srgb.I create mode 100644 panda/src/pnmimage/convert_srgb.cxx create mode 100644 panda/src/pnmimage/convert_srgb.h create mode 100644 panda/src/pnmimage/convert_srgb_sse2.cxx diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 5bb52227ca..db63d2bc9d 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -3204,7 +3204,8 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj, } extra_convert += "PyObject *" + param_name + "_long = PyNumber_Long(" + param_name + ");"; extra_param_check += " && " + param_name + "_long != NULL"; - pexpr_string = "PyLong_AsUnsignedLongLong(" + param_name + "_long)"; + pexpr_string = "(" + type->get_local_name(&parser) + ")" + + "PyLong_AsUnsignedLongLong(" + param_name + "_long)"; extra_cleanup += "Py_XDECREF(" + param_name + "_long);"; expected_params += "unsigned long long"; ++num_params; @@ -3219,7 +3220,8 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj, } extra_convert += "PyObject *" + param_name + "_long = PyNumber_Long(" + param_name + ");"; extra_param_check += " && " + param_name + "_long != NULL"; - pexpr_string = "PyLong_AsLongLong(" + param_name + "_long)"; + pexpr_string = "(" + type->get_local_name(&parser) + ")" + + "PyLong_AsLongLong(" + param_name + "_long)"; extra_cleanup += "Py_XDECREF(" + param_name + "_long);"; expected_params += "long long"; ++num_params; @@ -3234,7 +3236,8 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj, } extra_convert += "PyObject *" + param_name + "_long = PyNumber_Long(" + param_name + ");"; extra_param_check += " && " + param_name + "_long != NULL"; - pexpr_string = "PyLong_AsUnsignedLong(" + param_name + "_long)"; + pexpr_string = "(" + type->get_local_name(&parser) + ")" + + "PyLong_AsUnsignedLong(" + param_name + "_long)"; extra_cleanup += "Py_XDECREF(" + param_name + "_long);"; expected_params += "unsigned int"; ++num_params; diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 72d30a5dab..0be433b6d7 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -949,7 +949,7 @@ def CompileCxx(obj,src,opts): if PkgSkip("TOUCHINPUT") == 0: cmd += "/DWINVER=0x601 " cmd += "/Fo" + obj + " /nologo /c" - if (GetTargetArch() != 'x64' and PkgSkip("SSE2") == 0): + if GetTargetArch() != 'x64' and (not PkgSkip("SSE2") or 'SSE2' in opts): cmd += " /arch:SSE2" for x in ipath: cmd += " /I" + x for (opt,dir) in INCDIRECTORIES: @@ -1160,7 +1160,7 @@ def CompileCxx(obj,src,opts): if optlevel >= 4 or GetTarget() == "android": cmd += " -fno-rtti" - if PkgSkip("SSE2") == 0 and not arch.startswith("arm"): + if ('SSE2' in opts or not PkgSkip("SSE2")) and not arch.startswith("arm"): cmd += " -msse2" if optlevel >= 3: @@ -1705,7 +1705,7 @@ def RunGenPyCode(target, inputs, opts): if (PkgSkip("PYTHON") != 0): return - cmdstr = sys.executable + " " + cmdstr = BracketNameWithQuotes(SDK["PYTHONEXEC"]) + " " if sys.version_info >= (2, 6): cmdstr += "-B " @@ -1729,7 +1729,7 @@ def RunGenPyCode(target, inputs, opts): def FreezePy(target, inputs, opts): assert len(inputs) > 0 # Make sure this function isn't called before genpycode is run. - cmdstr = sys.executable + " " + cmdstr = BracketNameWithQuotes(SDK["PYTHONEXEC"]) + " " if sys.version_info >= (2, 6): cmdstr += "-B " @@ -1757,7 +1757,7 @@ def FreezePy(target, inputs, opts): def Package(target, inputs, opts): assert len(inputs) == 1 # Invoke the ppackage script. - command = sys.executable + " " + command = BracketNameWithQuotes(SDK["PYTHONEXEC"]) + " " if GetOptimizeOption(opts) >= 4: command += "-OO " @@ -3192,6 +3192,7 @@ if (not RUNTIME): OPTS=['DIR:panda/src/pnmimage', 'BUILDING:PANDA', 'ZLIB'] TargetAdd('p3pnmimage_composite1.obj', opts=OPTS, input='p3pnmimage_composite1.cxx') TargetAdd('p3pnmimage_composite2.obj', opts=OPTS, input='p3pnmimage_composite2.cxx') + TargetAdd('p3pnmimage_convert_srgb_sse2.obj', opts=OPTS+['SSE2'], input='convert_srgb_sse2.cxx') OPTS=['DIR:panda/src/pnmimage', 'ZLIB'] IGATEFILES=GetDirectoryContents('panda/src/pnmimage', ["*.h", "*_composite*.cxx"]) @@ -3621,6 +3622,7 @@ if (not RUNTIME): TargetAdd('libpanda.dll', input='p3pnmimagetypes_composite2.obj') TargetAdd('libpanda.dll', input='p3pnmimage_composite1.obj') TargetAdd('libpanda.dll', input='p3pnmimage_composite2.obj') + TargetAdd('libpanda.dll', input='p3pnmimage_convert_srgb_sse2.obj') TargetAdd('libpanda.dll', input='p3text_composite1.obj') TargetAdd('libpanda.dll', input='p3text_composite2.obj') TargetAdd('libpanda.dll', input='p3tform_composite1.obj') diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index d44903e921..08474cc445 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -41,6 +41,7 @@ #include "pbitops.h" #include "streamReader.h" #include "texturePeeker.h" +#include "convert_srgb.h" #ifdef HAVE_SQUISH #include @@ -131,46 +132,6 @@ struct DDSHeader { DDSCaps2 caps; }; -// This table is used for converting unsigned char texture values in an sRGB -// texture to linear RGB values, for use in mipmap generation. -static float srgb_to_lrgbf[256] = {0.000000f, 0.000304f, 0.000607f, 0.000911f, - 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f, - 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, - 0.006049f, 0.006512f, 0.006995f, 0.007499f, 0.008023f, 0.008568f, 0.009134f, - 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, - 0.014444f, 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, - 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f, 0.025187f, 0.026241f, - 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, - 0.035601f, 0.036889f, 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, - 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f, 0.054480f, - 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, - 0.068478f, 0.070360f, 0.072272f, 0.074214f, 0.076185f, 0.078187f, 0.080220f, - 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f, - 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, - 0.114435f, 0.116971f, 0.119538f, 0.122139f, 0.124772f, 0.127438f, 0.130136f, - 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, - 0.152926f, 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, - 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f, 0.191202f, 0.194618f, - 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, - 0.223228f, 0.226966f, 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, - 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f, 0.274677f, - 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, - 0.309469f, 0.313989f, 0.318547f, 0.323143f, 0.327778f, 0.332452f, 0.337164f, - 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f, - 0.376262f, 0.381326f, 0.386429f, 0.391572f, 0.396755f, 0.401978f, 0.407240f, - 0.412543f, 0.417885f, 0.423268f, 0.428690f, 0.434154f, 0.439657f, 0.445201f, - 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473531f, 0.479320f, 0.485150f, - 0.491021f, 0.496933f, 0.502886f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, - 0.533276f, 0.539479f, 0.545724f, 0.552011f, 0.558340f, 0.564712f, 0.571125f, - 0.577580f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, - 0.623960f, 0.630757f, 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, - 0.672443f, 0.679542f, 0.686685f, 0.693872f, 0.701102f, 0.708376f, 0.715694f, - 0.723055f, 0.730461f, 0.737910f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, - 0.775822f, 0.783538f, 0.791298f, 0.799103f, 0.806952f, 0.814847f, 0.822786f, - 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f, - 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, - 0.947307f, 0.955973f, 0.964686f, 0.973445f, 0.982251f, 0.991102f, 1.000000f}; - //////////////////////////////////////////////////////////////////// // Function: Texture::Constructor // Access: Published @@ -6990,7 +6951,13 @@ do_filter_2d_mipmap_pages(const CData *cdata, // We currently only support sRGB mipmap generation for // unsigned byte textures, due to our use of a lookup table. nassertv(cdata->_component_type == T_unsigned_byte); - filter_component = &filter_2d_unsigned_byte_srgb; + + if (has_sse2_sRGB_encode()) { + filter_component = &filter_2d_unsigned_byte_srgb_sse2; + } else { + filter_component = &filter_2d_unsigned_byte_srgb; + } + // Alpha is always linear. filter_alpha = &filter_2d_unsigned_byte; @@ -7140,7 +7107,13 @@ do_filter_3d_mipmap_level(const CData *cdata, // We currently only support sRGB mipmap generation for // unsigned byte textures, due to our use of a lookup table. nassertv(cdata->_component_type == T_unsigned_byte); - filter_component = &filter_3d_unsigned_byte_srgb; + + if (has_sse2_sRGB_encode()) { + filter_component = &filter_3d_unsigned_byte_srgb_sse2; + } else { + filter_component = &filter_3d_unsigned_byte_srgb; + } + // Alpha is always linear. filter_alpha = &filter_3d_unsigned_byte; @@ -7385,18 +7358,32 @@ filter_2d_unsigned_byte(unsigned char *&p, const unsigned char *&q, void Texture:: filter_2d_unsigned_byte_srgb(unsigned char *&p, const unsigned char *&q, size_t pixel_size, size_t row_size) { - float result = (srgb_to_lrgbf[q[0]] + - srgb_to_lrgbf[q[pixel_size]] + - srgb_to_lrgbf[q[row_size]] + - srgb_to_lrgbf[q[pixel_size + row_size]]) / 4.0f; + float result = (decode_sRGB_float(q[0]) + + decode_sRGB_float(q[pixel_size]) + + decode_sRGB_float(q[row_size]) + + decode_sRGB_float(q[pixel_size + row_size])); - // This is based on the formula out of the EXT_texture_sRGB - // specification, except the factors are multiplied with 255.0f. - if (result < 0.0031308f) { - *p = (unsigned char)(result * 3294.6f); - } else { - *p = (unsigned char)(269.025f * powf(result, 0.41666f) - 14.025f); - } + *p = encode_sRGB_uchar(result * 0.25f); + ++p; + ++q; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::filter_2d_unsigned_byte_srgb_sse2 +// Access: Public, Static +// Description: Averages a 2x2 block of pixel components into a +// single pixel component, for producing the next mipmap +// level. Increments p and q to the next component. +//////////////////////////////////////////////////////////////////// +void Texture:: +filter_2d_unsigned_byte_srgb_sse2(unsigned char *&p, const unsigned char *&q, + size_t pixel_size, size_t row_size) { + float result = (decode_sRGB_float(q[0]) + + decode_sRGB_float(q[pixel_size]) + + decode_sRGB_float(q[row_size]) + + decode_sRGB_float(q[pixel_size + row_size])); + + *p = encode_sRGB_uchar_sse2(result * 0.25f); ++p; ++q; } @@ -7470,22 +7457,40 @@ filter_3d_unsigned_byte(unsigned char *&p, const unsigned char *&q, void Texture:: filter_3d_unsigned_byte_srgb(unsigned char *&p, const unsigned char *&q, size_t pixel_size, size_t row_size, size_t page_size) { - float result = (srgb_to_lrgbf[q[0]] + - srgb_to_lrgbf[q[pixel_size]] + - srgb_to_lrgbf[q[row_size]] + - srgb_to_lrgbf[q[pixel_size + row_size]] + - srgb_to_lrgbf[q[page_size]] + - srgb_to_lrgbf[q[pixel_size + page_size]] + - srgb_to_lrgbf[q[row_size + page_size]] + - srgb_to_lrgbf[q[pixel_size + row_size + page_size]]) / 8.0f; + float result = (decode_sRGB_float(q[0]) + + decode_sRGB_float(q[pixel_size]) + + decode_sRGB_float(q[row_size]) + + decode_sRGB_float(q[pixel_size + row_size]) + + decode_sRGB_float(q[page_size]) + + decode_sRGB_float(q[pixel_size + page_size]) + + decode_sRGB_float(q[row_size + page_size]) + + decode_sRGB_float(q[pixel_size + row_size + page_size])); - // This is based on the formula out of the EXT_texture_sRGB - // specification, except the factors are multiplied with 255.0f. - if (result < 0.0031308f) { - *p = (unsigned char)(result * 3294.6f); - } else { - *p = (unsigned char)(269.025f * powf(result, 0.41666f) - 14.025f); - } + *p = encode_sRGB_uchar(result * 0.125f); + ++p; + ++q; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::filter_3d_unsigned_byte_srgb_sse2 +// Access: Public, Static +// Description: Averages a 2x2x2 block of pixel components into a +// single pixel component, for producing the next mipmap +// level. Increments p and q to the next component. +//////////////////////////////////////////////////////////////////// +void Texture:: +filter_3d_unsigned_byte_srgb_sse2(unsigned char *&p, const unsigned char *&q, + size_t pixel_size, size_t row_size, size_t page_size) { + float result = (decode_sRGB_float(q[0]) + + decode_sRGB_float(q[pixel_size]) + + decode_sRGB_float(q[row_size]) + + decode_sRGB_float(q[pixel_size + row_size]) + + decode_sRGB_float(q[page_size]) + + decode_sRGB_float(q[pixel_size + page_size]) + + decode_sRGB_float(q[row_size + page_size]) + + decode_sRGB_float(q[pixel_size + row_size + page_size])); + + *p = encode_sRGB_uchar_sse2(result * 0.125f); ++p; ++q; } diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index c8e0571aea..66e52ed7da 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -749,6 +749,9 @@ private: static void filter_2d_unsigned_byte_srgb(unsigned char *&p, const unsigned char *&q, size_t pixel_size, size_t row_size); + static void filter_2d_unsigned_byte_srgb_sse2(unsigned char *&p, + const unsigned char *&q, + size_t pixel_size, size_t row_size); static void filter_2d_unsigned_short(unsigned char *&p, const unsigned char *&q, size_t pixel_size, size_t row_size); @@ -763,6 +766,10 @@ private: const unsigned char *&q, size_t pixel_size, size_t row_size, size_t page_size); + static void filter_3d_unsigned_byte_srgb_sse2(unsigned char *&p, + const unsigned char *&q, + size_t pixel_size, size_t row_size, + size_t page_size); static void filter_3d_unsigned_short(unsigned char *&p, const unsigned char *&q, size_t pixel_size, size_t row_size, diff --git a/panda/src/pnmimage/convert_srgb.I b/panda/src/pnmimage/convert_srgb.I new file mode 100644 index 0000000000..e841748fb4 --- /dev/null +++ b/panda/src/pnmimage/convert_srgb.I @@ -0,0 +1,175 @@ +// Filename: convert_srgb.I +// Created by: rdb (29Oct14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: decode_sRGB_float +// Description: Decodes the sRGB-encoded unsigned char value to +// a linearized float in the range 0-1. +//////////////////////////////////////////////////////////////////// +CONSTEXPR float decode_sRGB_float(unsigned char val) { + return to_linear_float_table[val]; +} + +//////////////////////////////////////////////////////////////////// +// Function: encode_sRGB_float +// Description: Decodes the sRGB-encoded floating-point value in +// the range 0-1 to a linearized float in the range +// 0-1. Inputs outside this range produce invalid +// results. +//////////////////////////////////////////////////////////////////// +INLINE float decode_sRGB_float(float val) { + return (val <= 0.04045f) + ? (val * (1.f / 12.92f)) + : cpow((val + 0.055f) * (1.f / 1.055f), 2.4f); +} + +//////////////////////////////////////////////////////////////////// +// Function: decode_sRGB_uchar +// Description: Decodes the sRGB-encoded unsigned char value to +// a linearized unsigned char value. +//////////////////////////////////////////////////////////////////// +CONSTEXPR unsigned char decode_sRGB_uchar(unsigned char val) { + return to_linear_uchar_table[val]; +} + +//////////////////////////////////////////////////////////////////// +// Function: decode_sRGB_uchar +// Description: Decodes the sRGB-encoded floating-point value in +// the range 0-1 to a linearized unsigned char value. +// Inputs outside this range are clamped. +//////////////////////////////////////////////////////////////////// +INLINE unsigned char decode_sRGB_uchar(float val) { + return (val <= 0.04045f) + ? (unsigned char)(max(0.f, val) * (255.f / 12.92f) + 0.5f) + : (unsigned char)(cpow((min(val, 1.f) + 0.055f) * (1.f / 1.055f), 2.4f) * 255.f + 0.5f); +} + +//////////////////////////////////////////////////////////////////// +// Function: encode_sRGB_float +// Description: Encodes the linearized unsigned char value to an +// sRGB-encoded floating-point value in ther range 0-1. +//////////////////////////////////////////////////////////////////// +INLINE float +encode_sRGB_float(unsigned char val) { + // This seems like a very unlikely use case, so I didn't bother + // making a look-up table for this. + return (val == 0) ? 0 + : (1.055f * cpow((float)val * (1.f / 255.f), 0.41666f) - 0.055); +} + +//////////////////////////////////////////////////////////////////// +// Function: encode_sRGB_float +// Description: Encodes the linearized floating-point value in the +// range 0-1 to an sRGB-encoded float in the range +// 0-1. Inputs outside this range produce invalid +// results. +//////////////////////////////////////////////////////////////////// +INLINE float +encode_sRGB_float(float val) { + return (val < 0.0031308f) + ? (val * 12.92f) + : (1.055f * cpow(val, 0.41666f) - 0.055); +} + +//////////////////////////////////////////////////////////////////// +// Function: encode_sRGB_uchar +// Description: Encodes the linearized unsigned char value to an +// sRGB-encoded unsigned char value. +//////////////////////////////////////////////////////////////////// +CONSTEXPR unsigned char +encode_sRGB_uchar(unsigned char val) { + return to_srgb8_table[val]; +} + +//////////////////////////////////////////////////////////////////// +// Function: encode_sRGB_uchar +// Description: Encodes the linearized floating-point value in the +// range 0-1 to an sRGB-encoded unsigned char value. +// Inputs outside this range are clamped. +// +// When SSE2 support is known at compile time, this +// automatically uses an optimized version. Otherwise, +// it does not attempt runtime CPU detection. If you +// know that SSE2 is supported (ie. if the function +// has_sse2_sRGB_encode() returns true) you should +// call encode_sRGB_uchar_sse2 instead. +//////////////////////////////////////////////////////////////////// +INLINE unsigned char +encode_sRGB_uchar(float val) { +#if defined(__SSE2__) || (_M_IX86_FP >= 2) || defined(_M_X64) || defined(_M_AMD64) + // Use a highly optimized approximation that has more than enough + // accuracy for an unsigned char. + return encode_sRGB_uchar_sse2(val); +#else + return (val < 0.0031308f) + ? (unsigned char) (max(0.f, val) * 3294.6f + 0.5f) + : (unsigned char) (269.025f * cpow(min(val, 1.f), 0.41666f) - 13.525f); +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: encode_sRGB_uchar +// Description: Encodes the linearized floating-point color value +// an sRGB-encoded xel in the range 0-255. +// +// When SSE2 support is known at compile time, this +// automatically uses an optimized version. Otherwise, +// it does not attempt runtime CPU detection. If you +// know that SSE2 is supported (ie. if the function +// has_sse2_sRGB_encode() returns true) you should +// call encode_sRGB_uchar_sse2 instead. +//////////////////////////////////////////////////////////////////// +INLINE void +encode_sRGB_uchar(const LColorf &color, xel &into) { +#if defined(__SSE2__) || (_M_IX86_FP >= 2) || defined(_M_X64) || defined(_M_AMD64) + // SSE2 support compiled-in; we're guaranteed to have it. + encode_sRGB_uchar_sse2(color, into); +#else + // Boring, slow, non-SSE2 version. + PPM_ASSIGN(into, + encode_sRGB_uchar(color[0]), + encode_sRGB_uchar(color[1]), + encode_sRGB_uchar(color[2])); +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: encode_sRGB_uchar +// Description: Encodes the linearized floating-point color value +// an sRGB-encoded xel and alpha in the range 0-255. +// The alpha value is not sRGB-encoded. +// +// When SSE2 support is known at compile time, this +// automatically uses an optimized version. Otherwise, +// it does not attempt runtime CPU detection. If you +// know that SSE2 is supported (ie. if the function +// has_sse2_sRGB_encode() returns true) you should +// call encode_sRGB_uchar_sse2 instead. +//////////////////////////////////////////////////////////////////// +INLINE void +encode_sRGB_uchar(const LColorf &color, xel &into, xelval &into_alpha) { +#if defined(__SSE2__) || (_M_IX86_FP >= 2) || defined(_M_X64) || defined(_M_AMD64) + // SSE2 support compiled-in; we're guaranteed to have it. + encode_sRGB_uchar_sse2(color, into, into_alpha); +#else + // Boring, slow, non-SSE2 version. + PPM_ASSIGN(into, + encode_sRGB_uchar(color[0]), + encode_sRGB_uchar(color[1]), + encode_sRGB_uchar(color[2])); + + into_alpha = (xelval) (color[3] * 255.f + 0.5f); +#endif +} diff --git a/panda/src/pnmimage/convert_srgb.cxx b/panda/src/pnmimage/convert_srgb.cxx new file mode 100644 index 0000000000..ef27735d06 --- /dev/null +++ b/panda/src/pnmimage/convert_srgb.cxx @@ -0,0 +1,165 @@ +// Filename: convert_srgb.cxx +// Created by: rdb (13Nov14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "convert_srgb.h" + +#ifdef __GNUC__ +#include +#endif + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include +#endif + +// Lookup tables for converting from unsigned char formats. +ALIGN_64BYTE const +unsigned char to_srgb8_table[256] = { 0x00, 0x0d, 0x16, 0x1c, 0x22, 0x26, 0x2a, + 0x2e, 0x32, 0x35, 0x38, 0x3b, 0x3d, 0x40, 0x42, 0x45, 0x47, 0x49, 0x4b, 0x4d, + 0x4f, 0x51, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5d, 0x5f, 0x60, 0x62, 0x63, + 0x65, 0x66, 0x68, 0x69, 0x6a, 0x6c, 0x6d, 0x6e, 0x70, 0x71, 0x72, 0x73, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, + 0x91, 0x92, 0x93, 0x94, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, + 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa3, 0xa4, 0xa5, 0xa6, + 0xa7, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xad, 0xae, 0xaf, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb7, 0xb8, 0xb9, + 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbd, 0xbd, 0xbe, 0xbe, 0xbf, 0xc0, 0xc0, 0xc1, + 0xc2, 0xc2, 0xc3, 0xc4, 0xc4, 0xc5, 0xc5, 0xc6, 0xc7, 0xc7, 0xc8, 0xc8, 0xc9, + 0xca, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xcd, 0xce, 0xce, 0xcf, 0xd0, 0xd0, 0xd1, + 0xd1, 0xd2, 0xd2, 0xd3, 0xd4, 0xd4, 0xd5, 0xd5, 0xd6, 0xd6, 0xd7, 0xd7, 0xd8, + 0xd8, 0xd9, 0xda, 0xda, 0xdb, 0xdb, 0xdc, 0xdc, 0xdd, 0xdd, 0xde, 0xde, 0xdf, + 0xdf, 0xe0, 0xe0, 0xe1, 0xe2, 0xe2, 0xe3, 0xe3, 0xe4, 0xe4, 0xe5, 0xe5, 0xe6, + 0xe6, 0xe7, 0xe7, 0xe8, 0xe8, 0xe9, 0xe9, 0xea, 0xea, 0xeb, 0xeb, 0xec, 0xec, + 0xed, 0xed, 0xee, 0xee, 0xee, 0xef, 0xef, 0xf0, 0xf0, 0xf1, 0xf1, 0xf2, 0xf2, + 0xf3, 0xf3, 0xf4, 0xf4, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf8, 0xf8, + 0xf9, 0xf9, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfd, 0xfd, 0xfe, 0xfe, + 0xff, 0xff}; + +ALIGN_64BYTE const +unsigned char to_linear_uchar_table[256] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, + 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0b, + 0x0b, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x10, + 0x11, 0x11, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14, 0x14, 0x15, 0x16, 0x16, 0x17, + 0x17, 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1b, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, + 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23, 0x23, 0x24, 0x25, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4c, 0x4d, + 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0x5a, 0x5b, 0x5c, + 0x5d, 0x5f, 0x60, 0x61, 0x63, 0x64, 0x65, 0x67, 0x68, 0x69, 0x6b, 0x6c, 0x6d, + 0x6f, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f, 0x80, + 0x82, 0x83, 0x85, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8e, 0x90, 0x92, 0x93, 0x95, + 0x97, 0x98, 0x9a, 0x9c, 0x9d, 0x9f, 0xa1, 0xa3, 0xa4, 0xa6, 0xa8, 0xaa, 0xab, + 0xad, 0xaf, 0xb1, 0xb3, 0xb5, 0xb7, 0xb8, 0xba, 0xbc, 0xbe, 0xc0, 0xc2, 0xc4, + 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, + 0xe0, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xed, 0xef, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, + 0xfd, 0xff}; + +ALIGN_64BYTE +const float to_linear_float_table[256] = { 0, 0.000304f, 0.000607f, 0.000911f, + 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f, + 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, + 0.006049f, 0.006512f, 0.006995f, 0.007499f, 0.008023f, 0.008568f, 0.009134f, + 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, + 0.014444f, 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, + 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f, 0.025187f, 0.026241f, + 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, + 0.035601f, 0.036889f, 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, + 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f, 0.054480f, + 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, + 0.068478f, 0.070360f, 0.072272f, 0.074214f, 0.076185f, 0.078187f, 0.080220f, + 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f, + 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, + 0.114435f, 0.116971f, 0.119538f, 0.122139f, 0.124772f, 0.127438f, 0.130136f, + 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, + 0.152926f, 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, + 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f, 0.191202f, 0.194618f, + 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, + 0.223228f, 0.226966f, 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, + 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f, 0.274677f, + 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, + 0.309469f, 0.313989f, 0.318547f, 0.323143f, 0.327778f, 0.332452f, 0.337164f, + 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f, + 0.376262f, 0.381326f, 0.386429f, 0.391572f, 0.396755f, 0.401978f, 0.407240f, + 0.412543f, 0.417885f, 0.423268f, 0.428690f, 0.434154f, 0.439657f, 0.445201f, + 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473531f, 0.479320f, 0.485150f, + 0.491021f, 0.496933f, 0.502886f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, + 0.533276f, 0.539479f, 0.545724f, 0.552011f, 0.558340f, 0.564712f, 0.571125f, + 0.577580f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, + 0.623960f, 0.630757f, 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, + 0.672443f, 0.679542f, 0.686685f, 0.693872f, 0.701102f, 0.708376f, 0.715694f, + 0.723055f, 0.730461f, 0.737910f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, + 0.775822f, 0.783538f, 0.791298f, 0.799103f, 0.806952f, 0.814847f, 0.822786f, + 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f, + 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, + 0.947307f, 0.955973f, 0.964686f, 0.973445f, 0.982251f, 0.991102f, 1.000000f}; + + +#if defined(__SSE2__) || (_M_IX86_FP >= 2) || defined(_M_X64) || defined(_M_AMD64) +// SSE2 support enabled at compile time. No runtime detection mechanism needed. +bool +has_sse2_sRGB_encode() { + return true; +} + +#else +// SSE2 support not guaranteed. Use a runtime detection mechanism. + +bool +has_sse2_sRGB_encode() { +#if defined(__GNUC__) + unsigned int a, b, c, d; + static const bool has_support = + (__get_cpuid(1, &a, &b, &c, &d) == 1 && (d & 0x04000000) != 0); + +#elif defined(_WIN32) + static const bool has_support = + (IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE) != FALSE); + +#else + static const bool has_support = false; +#endif + + if (pnmimage_cat.is_debug()) { + static bool checked = false; + if (!checked) { +#if defined(__GNUC__) || defined(_WIN32) + if (has_support) { + pnmimage_cat.debug() + << "Runtime detection reports SSE2 instructions available: " + << "SSE2-optimized sRGB encoding routines enabled.\n"; + } else { + pnmimage_cat.debug() + << "Runtime detection reports SSE2 instructions unavailable: " + << "SSE2-optimized sRGB encoding routines disabled.\n"; + } +#else + pnmimage_cat.debug() + << "No runtime detection mechanism for SSE2 instructions available: " + << "SSE2-optimized sRGB encoding routines disabled.\n"; +#endif + checked = true; + } + } + + return has_support; +} + +#endif // __SSE2__ diff --git a/panda/src/pnmimage/convert_srgb.h b/panda/src/pnmimage/convert_srgb.h new file mode 100644 index 0000000000..6d59019d84 --- /dev/null +++ b/panda/src/pnmimage/convert_srgb.h @@ -0,0 +1,59 @@ +// Filename: convert_srgb.h +// Created by: rdb (13Nov14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef CONVERT_SRGB_H +#define CONVERT_SRGB_H + +#include "pandabase.h" +#include "luse.h" +#include "pnmimage_base.h" + +// The below functions can encode and decode sRGB colors in various +// representations. Some of them are implemented using look-up tables, +// some others using SSE2 intrinsics. +extern EXPCL_PANDA_PNMIMAGE const unsigned char to_srgb8_table[256]; +extern EXPCL_PANDA_PNMIMAGE const unsigned char to_linear_uchar_table[256]; +extern EXPCL_PANDA_PNMIMAGE const float to_linear_float_table[256]; + +EXPCL_PANDA_PNMIMAGE CONSTEXPR float decode_sRGB_float(unsigned char val); +EXPCL_PANDA_PNMIMAGE INLINE float decode_sRGB_float(float val); +EXPCL_PANDA_PNMIMAGE CONSTEXPR unsigned char decode_sRGB_uchar(unsigned char val); +EXPCL_PANDA_PNMIMAGE INLINE unsigned char decode_sRGB_uchar(float val); + +EXPCL_PANDA_PNMIMAGE INLINE float encode_sRGB_float(unsigned char val); +EXPCL_PANDA_PNMIMAGE INLINE float encode_sRGB_float(float val); +EXPCL_PANDA_PNMIMAGE CONSTEXPR unsigned char encode_sRGB_uchar(unsigned char val); +EXPCL_PANDA_PNMIMAGE INLINE unsigned char encode_sRGB_uchar(float val); + +// These functions convert more than one component in one go, +// which can be faster due to vectorization. +EXPCL_PANDA_PNMIMAGE INLINE void encode_sRGB_uchar(const LColorf &from, + xel &into); +EXPCL_PANDA_PNMIMAGE INLINE void encode_sRGB_uchar(const LColorf &from, + xel &into, xelval &into_alpha); + +// Use these functions if you know that SSE2 support is available. +// Otherwise, they will crash! +EXPCL_PANDA_PNMIMAGE unsigned char encode_sRGB_uchar_sse2(float val); +EXPCL_PANDA_PNMIMAGE void encode_sRGB_uchar_sse2(const LColorf &from, + xel &into); +EXPCL_PANDA_PNMIMAGE void encode_sRGB_uchar_sse2(const LColorf &from, + xel &into, xelval &into_alpha); + +// Use the following to find out if you can call either of the above. +EXPCL_PANDA_PNMIMAGE bool has_sse2_sRGB_encode(); + +#include "convert_srgb.I" + +#endif diff --git a/panda/src/pnmimage/convert_srgb_sse2.cxx b/panda/src/pnmimage/convert_srgb_sse2.cxx new file mode 100644 index 0000000000..e83a00394d --- /dev/null +++ b/panda/src/pnmimage/convert_srgb_sse2.cxx @@ -0,0 +1,151 @@ +// Filename: convert_srgb_sse2.cxx +// Created by: rdb (13Nov14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +// This file should always be compiled with SSE2 support. These +// functions will only be called when SSE2 support is detected at +// run-time. + +#include "convert_srgb.h" +#include "luse.h" + +#if defined(__SSE2__) || (_M_IX86_FP >= 2) || defined(_M_X64) || defined(_M_AMD64) + +#include +#include + +static INLINE __m128i _encode_sRGB_sse2_mul255(__m128 val) { + // This an SSE2-based approximation of the sRGB encode function. + // It has a maximum error of around 0.001, which is by far small + // enough for a uchar. It is also at least 10x as fast as the + // original; up to 40x when taking advantage of vectorization. + // Note that the fourth float is only multiplied with 255. + + // Part of the code in this function is derived from: + // http://stackoverflow.com/a/6486630/2135754 + + // Clamp to 0-1 range. + val = _mm_max_ps(val, _mm_set1_ps(0.0f)); + val = _mm_min_ps(val, _mm_set1_ps(1.0f)); + + // Pre-multiply with constant factor to adjust for exp bias. + __m128 xf = _mm_mul_ps(val, _mm_set1_ps(6.3307e18f)); + + // Approximate logarithm by... casting! + xf = _mm_cvtepi32_ps(_mm_castps_si128(xf)); + + // Multiply 'logarithm' by power. + xf = _mm_mul_ps(xf, _mm_set1_ps(2.0f / 3.0f)); + + // Reverse operation of above: cast the other way. + xf = _mm_castsi128_ps(_mm_cvtps_epi32(xf)); + + // Make an overestimate and an underestimate. + __m128 xover = _mm_mul_ps(val, xf); + __m128 xunder = _mm_mul_ps(_mm_mul_ps(val, val), + _mm_rsqrt_ps(xf)); + + // Average the two factors, with a slight bias. + __m128 xavg = _mm_mul_ps(_mm_add_ps(xover, xunder), + _mm_set1_ps(0.5286098f)); + + // Take square root twice. Note that this is faster than + // the more expensive _mm_sqrt_ps instruction. + xavg = _mm_mul_ps(xavg, _mm_rsqrt_ps(xavg)); + xavg = _mm_mul_ps(xavg, _mm_rsqrt_ps(xavg)); + + // Bring it into the correct range. These factors are determined + // not on the basis of accuracy, but are chosen such that the + // decoder lookup table produces an equivalent result for any value. + xavg = _mm_mul_ps(xavg, _mm_set1_ps(269.122f)); + xavg = _mm_sub_ps(xavg, _mm_set1_ps(13.55f)); + + // Compute the linear section. This is also the path that + // the alpha channel takes, so we set the alpha multiplier + // to 255 (since alpha is not sRGB-converted). + __m128 lval = _mm_mul_ps(val, + _mm_set_ps(255.0f, 3294.6f, 3294.6f, 3294.6f)); + + lval = _mm_add_ps(lval, _mm_set1_ps(0.5f)); + + // Decide which version to return. Rig the alpha + // comparator to always fail so that the linear path + // is always chosen for alpha. + __m128 mask = _mm_cmpge_ps(val, + _mm_set_ps(2.0f, 0.0031308f, 0.0031308f, 0.0031308f)); + + // This is a non-branching way to return one or the other value. + return _mm_cvttps_epi32(_mm_or_ps( + _mm_and_ps(mask, xavg), + _mm_andnot_ps(mask, lval))); +} + +unsigned char +encode_sRGB_uchar_sse2(float val) { + // Running only a single component through this function is still + // way faster than the equivalent non-SSE2 version. + return (unsigned char) + _mm_extract_epi32(_encode_sRGB_sse2_mul255(_mm_set1_ps(val)), 0); +} + +void +encode_sRGB_uchar_sse2(const LColorf &color, xel &into) { +#ifdef LINMATH_ALIGN + __m128 vec = _mm_load_ps(color.get_data()); +#else + __m128 vec = _mm_loadu_ps(color.get_data()); +#endif + + __m128i vals = _encode_sRGB_sse2_mul255(vec); + into.r = _mm_extract_epi32(vals, 0); + into.g = _mm_extract_epi32(vals, 1); + into.b = _mm_extract_epi32(vals, 2); +} + +void +encode_sRGB_uchar_sse2(const LColorf &color, xel &into, xelval &into_alpha) { +#ifdef LINMATH_ALIGN + __m128 vec = _mm_load_ps(color.get_data()); +#else + __m128 vec = _mm_loadu_ps(color.get_data()); +#endif + + __m128i vals = _encode_sRGB_sse2_mul255(vec); + into.r = _mm_extract_epi32(vals, 0); + into.g = _mm_extract_epi32(vals, 1); + into.b = _mm_extract_epi32(vals, 2); + into_alpha = _mm_extract_epi32(vals, 3); +} + +#else +// Somehow we're still compiling this without SSE2 support. We'll +// still have to define these functions, but emit a warning that the +// build system isn't configured properly. +#warning convert_srgb_sse2.cxx is being compiled without SSE2 support! + +unsigned char +encode_sRGB_uchar_sse2(float val) { + return encode_sRGB_uchar(val); +} + +void +encode_sRGB_uchar_sse2(const LColorf &color, xel &into) { + encode_sRGB_uchar(color, into); +} + +void +encode_sRGB_uchar_sse2(const LColorf &color, xel &into, xelval &into_alpha) { + encode_sRGB_uchar(color, into, into_alpha); +} + +#endif diff --git a/panda/src/pnmimage/p3pnmimage_composite1.cxx b/panda/src/pnmimage/p3pnmimage_composite1.cxx index 0e290cbc95..85dfe7f0a1 100644 --- a/panda/src/pnmimage/p3pnmimage_composite1.cxx +++ b/panda/src/pnmimage/p3pnmimage_composite1.cxx @@ -1,4 +1,5 @@ #include "config_pnmimage.cxx" +#include "convert_srgb.cxx" #include "pfmFile.cxx" #include "pnm-image-filter.cxx" #include "pnmbitio.cxx" diff --git a/panda/src/tinydisplay/zbuffer.h b/panda/src/tinydisplay/zbuffer.h index a4c8a2015c..46190ef4e6 100644 --- a/panda/src/tinydisplay/zbuffer.h +++ b/panda/src/tinydisplay/zbuffer.h @@ -75,7 +75,7 @@ typedef unsigned int ZPOINT; ((((unsigned int)(a) << 24) & 0xff000000) | (((unsigned int)(r) << 16) & 0xff0000) | (((unsigned int)(g) << 8) & 0xff00) | (unsigned int)(b)) #define SRGB_TO_PIXEL(r,g,b) \ - ((encode_sRGB[(unsigned int)(r) >> 4] << 16) | (encode_sRGB10[(unsigned int)(g) >> 4] << 8) | (encode_sRGB[(unsigned int)(b) >> 4])) + ((encode_sRGB[(unsigned int)(r) >> 4] << 16) | (encode_sRGB[(unsigned int)(g) >> 4] << 8) | (encode_sRGB[(unsigned int)(b) >> 4])) #define SRGBA_TO_PIXEL(r,g,b,a) \ ((((unsigned int)(a) << 16) & 0xff000000) | (encode_sRGB[(unsigned int)(r) >> 4] << 16) | (encode_sRGB[(unsigned int)(g) >> 4] << 8) | (encode_sRGB[(unsigned int)(b) >> 4])) From 97c24c9ef01e263c6497ae92b2261f17e15122c8 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 1 Mar 2015 17:32:20 +0100 Subject: [PATCH 31/32] Fix a Cg crash with GL_BGRA color arrays, on NVIDIA cards this time --- panda/src/glstuff/glCgShaderContext_src.cxx | 15 ++++----------- panda/src/glstuff/glCgShaderContext_src.h | 1 - 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/panda/src/glstuff/glCgShaderContext_src.cxx b/panda/src/glstuff/glCgShaderContext_src.cxx index 85b18b6f9d..0b05426529 100755 --- a/panda/src/glstuff/glCgShaderContext_src.cxx +++ b/panda/src/glstuff/glCgShaderContext_src.cxx @@ -41,7 +41,6 @@ CLP(CgShaderContext):: CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext(s) { _glgsg = glgsg; _cg_program = 0; - _glsl_profile = false; nassertv(s->get_language() == Shader::SL_Cg); @@ -63,10 +62,6 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte release_resources(); } else { - if (cgGetProgramProfile(_cg_program) == CG_PROFILE_GLSLC) { - _glsl_profile = true; - } - cgGLLoadProgram(_cg_program); CGerror error = cgGetError(); if (error != CG_NO_ERROR) { @@ -412,7 +407,7 @@ disable_shader_vertex_arrays() { CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno]; if (p == 0) continue; - if (_glsl_profile && cgGetParameterBaseResource(p) == CG_ATTR0) { + if (cgGetParameterBaseResource(p) == CG_ATTR0) { int index = cgGetParameterResourceIndex(p); if (index >= 8) { _glgsg->_glClientActiveTexture(GL_TEXTURE0 + (index - 8)); @@ -501,11 +496,9 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) { num_values = GL_BGRA; } - // This is truly the most preposterous hack. When using the GLSL - // profiles, cgGLSetParameterPointer relies on the the driver mapping - // standard attributes to fixed indices (and breaking the spec doing - // so), which only the NVIDIA drivers do. Unbelievable. - if (_glsl_profile && cgGetParameterBaseResource(p) == CG_ATTR0) { + // cgGLSetParameterPointer is just stupidly bugged on every level. + // Sigh. This seems to work on both NVIDIA and AMD cards now. + if (cgGetParameterBaseResource(p) == CG_ATTR0) { int index = cgGetParameterResourceIndex(p); switch (index) { case 0: // gl_Vertex diff --git a/panda/src/glstuff/glCgShaderContext_src.h b/panda/src/glstuff/glCgShaderContext_src.h index b5d45d4aaa..16dd9bcdb2 100755 --- a/panda/src/glstuff/glCgShaderContext_src.h +++ b/panda/src/glstuff/glCgShaderContext_src.h @@ -52,7 +52,6 @@ public: private: CGprogram _cg_program; - bool _glsl_profile; pvector _cg_parameter_map; From d11cafc374e4a5a7e60e9cbef563caba53cf1725 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 2 Mar 2015 16:18:55 +0100 Subject: [PATCH 32/32] Replace SSE4 instruction with SSE2 instruction --- panda/src/pnmimage/convert_srgb_sse2.cxx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/panda/src/pnmimage/convert_srgb_sse2.cxx b/panda/src/pnmimage/convert_srgb_sse2.cxx index e83a00394d..8121eccc8d 100644 --- a/panda/src/pnmimage/convert_srgb_sse2.cxx +++ b/panda/src/pnmimage/convert_srgb_sse2.cxx @@ -95,7 +95,7 @@ encode_sRGB_uchar_sse2(float val) { // Running only a single component through this function is still // way faster than the equivalent non-SSE2 version. return (unsigned char) - _mm_extract_epi32(_encode_sRGB_sse2_mul255(_mm_set1_ps(val)), 0); + _mm_extract_epi16(_encode_sRGB_sse2_mul255(_mm_set1_ps(val)), 0); } void @@ -107,9 +107,9 @@ encode_sRGB_uchar_sse2(const LColorf &color, xel &into) { #endif __m128i vals = _encode_sRGB_sse2_mul255(vec); - into.r = _mm_extract_epi32(vals, 0); - into.g = _mm_extract_epi32(vals, 1); - into.b = _mm_extract_epi32(vals, 2); + into.r = _mm_extract_epi16(vals, 0); + into.g = _mm_extract_epi16(vals, 2); + into.b = _mm_extract_epi16(vals, 4); } void @@ -121,10 +121,10 @@ encode_sRGB_uchar_sse2(const LColorf &color, xel &into, xelval &into_alpha) { #endif __m128i vals = _encode_sRGB_sse2_mul255(vec); - into.r = _mm_extract_epi32(vals, 0); - into.g = _mm_extract_epi32(vals, 1); - into.b = _mm_extract_epi32(vals, 2); - into_alpha = _mm_extract_epi32(vals, 3); + into.r = _mm_extract_epi16(vals, 0); + into.g = _mm_extract_epi16(vals, 2); + into.b = _mm_extract_epi16(vals, 4); + into_alpha = _mm_extract_epi16(vals, 6); } #else