mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-10-30 08:17:55 +00:00
Official files
This commit is contained in:
parent
b7aa710d9f
commit
23139d101d
11418 changed files with 2635555 additions and 0 deletions
3
build/.gitignore
vendored
Normal file
3
build/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
libpandadna/
|
||||
built/
|
||||
*.pdb
|
72
build/data/NiraiStart.py
Normal file
72
build/data/NiraiStart.py
Normal file
|
@ -0,0 +1,72 @@
|
|||
from panda3d.core import *
|
||||
import __builtin__, os, sys
|
||||
import aes
|
||||
|
||||
import niraidata
|
||||
|
||||
# Config
|
||||
prc = niraidata.CONFIG
|
||||
iv, key, prc = prc[:16], prc[16:32], prc[32:]
|
||||
prc = aes.decrypt(prc, key, iv)
|
||||
|
||||
for line in prc.split('\n'):
|
||||
line = line.strip()
|
||||
if line:
|
||||
loadPrcFileData('nirai config', line)
|
||||
|
||||
del prc
|
||||
del iv
|
||||
del key
|
||||
|
||||
# DC
|
||||
__builtin__.dcStream = StringStream()
|
||||
|
||||
dc = niraidata.DC
|
||||
iv, key, dc = dc[:16], dc[16:32], dc[32:]
|
||||
dc = aes.decrypt(dc, key, iv)
|
||||
|
||||
dcStream.setData(dc)
|
||||
del dc
|
||||
del iv
|
||||
del key
|
||||
|
||||
# Resources
|
||||
# TO DO: Sign and verify the phases to prevent editing.
|
||||
|
||||
vfs = VirtualFileSystem.getGlobalPtr()
|
||||
mfs = [3, 3.5, 4, 5, 5.5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||
abort = False
|
||||
|
||||
for mf in mfs:
|
||||
filename = 'resources/default/phase_%s.mf' % mf
|
||||
if not os.path.isfile(filename):
|
||||
print 'Phase %s not found' % filename
|
||||
abort = True
|
||||
break
|
||||
|
||||
mf = Multifile()
|
||||
mf.openRead(filename)
|
||||
|
||||
if not vfs.mount(mf, '/', 0):
|
||||
print 'Unable to mount %s' % filename
|
||||
abort = True
|
||||
break
|
||||
|
||||
# Packs
|
||||
pack = os.environ.get('TT_STRIDE_CONTENT_PACK')
|
||||
import glob
|
||||
if pack and pack != 'default':
|
||||
print 'Loading content pack', pack
|
||||
for file in glob.glob('resources/%s/*.mf' % pack):
|
||||
mf = Multifile()
|
||||
mf.openReadWrite(Filename(file))
|
||||
names = mf.getSubfileNames()
|
||||
for name in names:
|
||||
ext = os.path.splitext(name)[1]
|
||||
if ext not in ['.jpg', '.jpeg', '.ogg', '.rgb']:
|
||||
mf.removeSubfile(name)
|
||||
vfs.mount(mf, Filename('/'), 0)
|
||||
|
||||
if not abort:
|
||||
# Run
|
||||
import toontown.toonbase.ToontownStart
|
3
build/linux/aes-to-so.sh
Normal file
3
build/linux/aes-to-so.sh
Normal file
|
@ -0,0 +1,3 @@
|
|||
gcc -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -fPIC -DMAJOR_VERSION=1 -DMINOR_VERSION=0 -I/usr/include -I/usr/include/python2.7 -lstdc++ -lssl -lcrypto -c ../nirai/src/aes.cxx -c -o ../nirai/src/aes.o
|
||||
|
||||
gcc -shared ../nirai/src/aes.o -L/usr/local/lib -lstdc++ -lssl -lcrypto -o ../nirai/src/aes.so
|
2
build/linux/ubuntu-build-panda3d.sh
Normal file
2
build/linux/ubuntu-build-panda3d.sh
Normal file
|
@ -0,0 +1,2 @@
|
|||
cd ../nirai/panda3d
|
||||
python2.7 makepanda/makepanda.py --everything --no-contrib --no-fmodex --no-physx --no-bullet --no-pview --no-pandatool --no-swscale --no-swresample --no-speedtree --no-vrpn --no-artoolkit --no-opencv --no-directcam --no-vision --no-rocket --no-awesomium --no-deploytools --no-skel --no-ffmpeg --no-eigen --static
|
141
build/make.py
Normal file
141
build/make.py
Normal file
|
@ -0,0 +1,141 @@
|
|||
from panda3d.core import *
|
||||
|
||||
import argparse, struct
|
||||
import sys, glob
|
||||
import os
|
||||
|
||||
sys.path.append('nirai/src')
|
||||
|
||||
from niraitools import *
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--compile-cxx', '-c', action='store_true',
|
||||
help='Compile the CXX codes and generate stride.exe into built.')
|
||||
parser.add_argument('--make-nri', '-n', action='store_true',
|
||||
help='Generate stride NRI.')
|
||||
parser.add_argument('--make-mfs', '-m', action='store_true',
|
||||
help='Make multifiles')
|
||||
args = parser.parse_args()
|
||||
|
||||
if not os.path.exists('built'):
|
||||
os.mkdir('built')
|
||||
|
||||
def niraicall_obfuscate(code):
|
||||
# We'll obfuscate if len(code) % 4 == 0
|
||||
# This way we make sure both obfuscated and non-obfuscated code work.
|
||||
if len(code) % 4:
|
||||
return False, None
|
||||
|
||||
# Reverse
|
||||
code = code[::-1]
|
||||
|
||||
# XOR
|
||||
key = ['B', 'A', 'Q', 'J', 'R', 'P', 'Z', 'P', 'A', 'H', 'U', 'T']
|
||||
output = []
|
||||
|
||||
for i in range(len(code)):
|
||||
xor_num = ord(code[i]) ^ ord(key[i % len(key)])
|
||||
output.append(chr(xor_num))
|
||||
|
||||
code = ''.join(output)
|
||||
|
||||
return True, code
|
||||
|
||||
niraimarshal.niraicall_obfuscate = niraicall_obfuscate
|
||||
|
||||
class StridePackager(NiraiPackager):
|
||||
HEADER = 'TTSTRIDE'
|
||||
BASEDIR = '..' + os.sep
|
||||
|
||||
def __init__(self, outfile, configPath=None):
|
||||
NiraiPackager.__init__(self, outfile)
|
||||
self.__manglebase = self.get_mangle_base(self.BASEDIR)
|
||||
self.add_panda3d_dirs()
|
||||
self.add_default_lib()
|
||||
self.globalConfigPath = configPath
|
||||
|
||||
def add_source_dir(self, dir):
|
||||
self.add_directory(self.BASEDIR + dir, mangler=self.__mangler)
|
||||
|
||||
def add_data_file(self, file):
|
||||
mb = self.get_mangle_base('data/')
|
||||
self.add_file('data/%s.py' % file, mangler=lambda x: x[mb:])
|
||||
|
||||
def __mangler(self, name):
|
||||
if name.endswith('AI') or name.endswith('UD') or name in ('ToontownAIRepository', 'ToontownUberRepository',
|
||||
'ToontownInternalRepository', 'ServiceStart'):
|
||||
if not 'NonRepeatableRandomSource' in name:
|
||||
return ''
|
||||
|
||||
return name[self.__manglebase:].strip('.')
|
||||
|
||||
def generate_niraidata(self):
|
||||
print 'Generating niraidata'
|
||||
if self.globalConfigPath is not None:
|
||||
config = self.get_file_contents(self.globalConfigPath)
|
||||
else:
|
||||
config = self.get_file_contents('../dependencies/config/general.prc')
|
||||
config += '\n\n' + self.get_file_contents('../dependencies/config/release/qa.prc')
|
||||
|
||||
config_iv = self.generate_key(16)
|
||||
config_key = self.generate_key(16)
|
||||
config = config_iv + config_key + aes.encrypt(config, config_key, config_iv)
|
||||
niraidata = 'CONFIG = %r' % config
|
||||
|
||||
# DC
|
||||
niraidata += '\nDC = %r' % self.get_file_contents('../dependencies/astron/dclass/stride.dc', True)
|
||||
self.add_module('niraidata', niraidata, compile=True)
|
||||
|
||||
def process_modules(self):
|
||||
# TODO: Compression
|
||||
dg = Datagram()
|
||||
dg.addUint32(len(self.modules))
|
||||
for moduleName in self.modules:
|
||||
data, size = self.modules[moduleName]
|
||||
|
||||
dg.addString(moduleName)
|
||||
dg.addInt32(size)
|
||||
dg.appendData(data)
|
||||
|
||||
data = dg.getMessage()
|
||||
iv = self.generate_key(16)
|
||||
key = self.generate_key(16)
|
||||
fixed_key = ''.join(chr((i ^ (7 * i + 16)) % ((i + 5) * 3)) for i in xrange(16))
|
||||
fixed_iv = ''.join(chr((i ^ (2 * i + 53)) % ((i + 9) * 6)) for i in xrange(16))
|
||||
securekeyandiv = aes.encrypt(iv + key, fixed_key, fixed_iv)
|
||||
return securekeyandiv + aes.encrypt(data, key, iv)
|
||||
|
||||
# Compile the engine
|
||||
if args.compile_cxx:
|
||||
compiler = NiraiCompiler('stride.exe', libs=set(glob.glob('libpandadna/libpandadna.dir/Release/*.obj')))
|
||||
|
||||
compiler.add_nirai_files()
|
||||
compiler.add_source('src/stride.cxx')
|
||||
|
||||
compiler.run()
|
||||
|
||||
# Compile the game data
|
||||
if args.make_nri:
|
||||
pkg = StridePackager('built/TTSData.bin')
|
||||
|
||||
pkg.add_source_dir('otp')
|
||||
pkg.add_source_dir('toontown')
|
||||
|
||||
pkg.add_data_file('NiraiStart')
|
||||
|
||||
pkg.generate_niraidata()
|
||||
|
||||
pkg.write_out()
|
||||
|
||||
if args.make_mfs:
|
||||
os.chdir('../resources')
|
||||
cmd = ''
|
||||
for phasenum in ['3', '3.5', '4', '5', '5.5', '6', '7', '8', '9', '10', '11', '12', '13']:
|
||||
print 'phase_%s' % (phasenum)
|
||||
cmd = 'multify -cf ../build/built/resources/default/phase_%s.mf phase_%s' % (phasenum, phasenum)
|
||||
p = subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr)
|
||||
v = p.wait()
|
||||
|
||||
if v != 0:
|
||||
print 'The following command returned non-zero value (%d): %s' % (v, cmd[:100] + '...')
|
||||
sys.exit(1)
|
4
build/nirai/panda3d/.gitignore
vendored
Normal file
4
build/nirai/panda3d/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/built_x64
|
||||
/built
|
||||
/thirdparty
|
||||
/targetroot
|
15
build/nirai/panda3d/.travis.yml
Normal file
15
build/nirai/panda3d/.travis.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
before_script:
|
||||
- sudo apt-get install python-dev libpng-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libjpeg-dev libopenal-dev libode-dev nvidia-cg-toolkit
|
||||
script: python makepanda/makepanda.py --everything --verbose --git-commit $TRAVIS_COMMIT --installer --threads 2
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "chat.freenode.net#panda3d"
|
||||
on_success: change
|
||||
on_failure: always
|
||||
use_notice: true
|
||||
skip_join: true
|
30
build/nirai/panda3d/LICENSE
Normal file
30
build/nirai/panda3d/LICENSE
Normal file
|
@ -0,0 +1,30 @@
|
|||
Copyright (c) 2008, Carnegie Mellon University.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of Carnegie Mellon University nor the names of
|
||||
other contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
(This is the Modified BSD License. See also
|
||||
http://www.opensource.org/licenses/bsd-license.php )
|
47
build/nirai/panda3d/README.md
Normal file
47
build/nirai/panda3d/README.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
Nirai's Panda3D
|
||||
=======
|
||||
|
||||
Panda3D is a game engine, a framework for 3D rendering and game development for
|
||||
Python and C++ programs. Panda3D is open-source and free for any purpose,
|
||||
including commercial ventures, thanks to its
|
||||
[liberal license](https://www.panda3d.org/license.php). To learn more about
|
||||
Panda3D's capabilities, visit the [gallery](https://www.panda3d.org/gallery.php)
|
||||
and the [feature list](https://www.panda3d.org/features.php). To learn how to
|
||||
use Panda3D, check the [documentation](https://www.panda3d.org/documentation.php)
|
||||
resources. If you get stuck, ask for help from our active
|
||||
[community](https://www.panda3d.org/community.php).
|
||||
|
||||
Panda3D is licensed under the Modified BSD License. See the LICENSE file for
|
||||
more details.
|
||||
|
||||
Building Panda3D
|
||||
================
|
||||
|
||||
Windows
|
||||
-------
|
||||
|
||||
We currently build using the Microsoft Visual C++ 2010 compiler. You do not
|
||||
need Microsoft Visual Studio to build Panda3D, though - the relevant compilers
|
||||
are included as part of the Windows 7.1 SDK.
|
||||
|
||||
You will also need to have the third-party dependency libraries available for
|
||||
the build scripts to use. These are available from Nirai organization.
|
||||
After acquiring these dependencies, you may simply build Panda3D from the
|
||||
command prompt using the following command:
|
||||
|
||||
```bash
|
||||
compile.bat
|
||||
postbuild.bat
|
||||
```
|
||||
|
||||
_postbuild_ cleans up _built_ dir.
|
||||
|
||||
Linux
|
||||
-----
|
||||
|
||||
TBA
|
||||
|
||||
Mac OS X
|
||||
--------
|
||||
|
||||
TBA
|
2
build/nirai/panda3d/compile.bat
Normal file
2
build/nirai/panda3d/compile.bat
Normal file
|
@ -0,0 +1,2 @@
|
|||
@echo off
|
||||
thirdparty\win-python\python makepanda/makepanda.py --everything --no-contrib --no-fmodex --no-physx --no-bullet --no-pview --no-pandatool --no-swscale --no-swresample --no-speedtree --no-vrpn --no-artoolkit --no-opencv --no-directcam --no-vision --no-rocket --no-awesomium --no-deploytools --no-skel --no-ffmpeg --no-eigen --static %*
|
9
build/nirai/panda3d/contrib/.gitignore
vendored
Normal file
9
build/nirai/panda3d/contrib/.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
*.pyc
|
||||
*.pyo
|
||||
/__init__.py
|
||||
# These are files that are generated within the source tree by the
|
||||
# ppremake system.
|
||||
Makefile
|
||||
pp.dep
|
||||
/built/
|
||||
Opt?-*
|
60
build/nirai/panda3d/contrib/Package.pp
Normal file
60
build/nirai/panda3d/contrib/Package.pp
Normal file
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// Package.pp
|
||||
//
|
||||
// This file defines certain configuration variables that are to be
|
||||
// written into the various make scripts. It is processed by ppremake
|
||||
// (along with the Sources.pp files in each of the various
|
||||
// contribories) to generate build scripts appropriate to each
|
||||
// environment.
|
||||
//
|
||||
// This is the package-specific file, which should be at the top of
|
||||
// every source hierarchy. It generally gets the ball rolling, and is
|
||||
// responsible for explicitly including all of the relevent Config.pp
|
||||
// files.
|
||||
|
||||
// What is the name and version of this source tree?
|
||||
#if $[eq $[PACKAGE],]
|
||||
#define PACKAGE contrib
|
||||
#define VERSION 0.80
|
||||
#endif
|
||||
|
||||
|
||||
// Where should we find the PANDA source contribory?
|
||||
#if $[PANDA_SOURCE]
|
||||
#define PANDA_SOURCE $[unixfilename $[PANDA_SOURCE]]
|
||||
#elif $[or $[CTPROJS],$[PANDA]]
|
||||
// If we are presently attached, use the environment variable.
|
||||
#define PANDA_SOURCE $[unixfilename $[PANDA]]
|
||||
#if $[eq $[PANDA],]
|
||||
#error You seem to be attached to some trees, but not PANDA!
|
||||
#endif
|
||||
#else
|
||||
// Otherwise, if we are not attached, we guess that the source is a
|
||||
// sibling contribory to this source root.
|
||||
#define PANDA_SOURCE $[standardize $[TOPDIR]/../panda]
|
||||
#endif
|
||||
|
||||
// Where should we install CONTRIB?
|
||||
#if $[CONTRIB_INSTALL]
|
||||
#define CONTRIB_INSTALL $[unixfilename $[CONTRIB_INSTALL]]
|
||||
#elif $[CTPROJS]
|
||||
#set CONTRIB $[unixfilename $[CONTRIB]]
|
||||
#define CONTRIB_INSTALL $[CONTRIB]/built
|
||||
#if $[eq $[CONTRIB],]
|
||||
#error You seem to be attached to some trees, but not CONTRIB!
|
||||
#endif
|
||||
#else
|
||||
#defer CONTRIB_INSTALL $[unixfilename $[INSTALL_DIR]]
|
||||
#endif
|
||||
|
||||
// Also get the PANDA Package file and everything that includes.
|
||||
#if $[not $[isfile $[PANDA_SOURCE]/Package.pp]]
|
||||
#printvar PANDA_SOURCE
|
||||
#error PANDA source contribory not found from contrib! Are you attached properly?
|
||||
#endif
|
||||
|
||||
#include $[PANDA_SOURCE]/Package.pp
|
||||
|
||||
// Define the inter-tree dependencies.
|
||||
#define NEEDS_TREES panda $[NEEDS_TREES]
|
||||
#define DEPENDABLE_HEADER_DIRS $[DEPENDABLE_HEADER_DIRS] $[PANDA_INSTALL]/include
|
10
build/nirai/panda3d/contrib/Sources.pp
Normal file
10
build/nirai/panda3d/contrib/Sources.pp
Normal file
|
@ -0,0 +1,10 @@
|
|||
// This is the toplevel directory for a package.
|
||||
|
||||
#define DIR_TYPE toplevel
|
||||
|
||||
#define REQUIRED_TREES dtool panda
|
||||
|
||||
#define EXTRA_DIST \
|
||||
Sources.pp Config.pp Package.pp
|
||||
|
||||
#define PYTHON_PACKAGE 1
|
4
build/nirai/panda3d/contrib/src/Sources.pp
Normal file
4
build/nirai/panda3d/contrib/src/Sources.pp
Normal file
|
@ -0,0 +1,4 @@
|
|||
// This is a group directory: a directory level above a number of
|
||||
// source subdirectories.
|
||||
|
||||
#define DIR_TYPE group
|
82
build/nirai/panda3d/contrib/src/ai/Sources.pp
Normal file
82
build/nirai/panda3d/contrib/src/ai/Sources.pp
Normal file
|
@ -0,0 +1,82 @@
|
|||
#define LOCAL_LIBS p3contribbase
|
||||
#define BUILDING_DLL BUILDING_PANDAAI
|
||||
|
||||
#define OTHER_LIBS \
|
||||
panda:c \
|
||||
p3express:c p3putil:c p3pandabase:c pandaexpress:m \
|
||||
p3interrogatedb:c p3prc:c p3dconfig:c p3dtoolconfig:m \
|
||||
p3dtoolutil:c p3dtoolbase:c p3dtool:m
|
||||
|
||||
#begin lib_target
|
||||
#define TARGET pandaai
|
||||
|
||||
#define COMBINED_SOURCES p3ai_composite1.cxx
|
||||
|
||||
#define SOURCES \
|
||||
aiBehaviors.h \
|
||||
aiCharacter.h \
|
||||
aiGlobals.h \
|
||||
aiNode.h \
|
||||
aiPathFinder.h \
|
||||
aiWorld.h \
|
||||
arrival.h \
|
||||
config_ai.h \
|
||||
evade.h \
|
||||
flee.h \
|
||||
flock.h \
|
||||
aiGlobals.h \
|
||||
meshNode.h \
|
||||
obstacleAvoidance.h \
|
||||
pathFind.h \
|
||||
pathFollow.h \
|
||||
pursue.h \
|
||||
seek.h \
|
||||
wander.h
|
||||
|
||||
#define INCLUDED_SOURCES \
|
||||
aiBehaviors.cxx \
|
||||
aiCharacter.cxx \
|
||||
aiNode.cxx \
|
||||
aiPathFinder.cxx \
|
||||
aiWorld.cxx \
|
||||
p3ai_composite.cxx \
|
||||
p3ai_composite1.cxx \
|
||||
arrival.cxx \
|
||||
config_ai.cxx \
|
||||
evade.cxx \
|
||||
flee.cxx \
|
||||
flock.cxx \
|
||||
meshNode.cxx \
|
||||
obstacleAvoidance.cxx \
|
||||
pathFind.cxx \
|
||||
pathFollow.cxx \
|
||||
pursue.cxx \
|
||||
seek.cxx \
|
||||
wander.cxx
|
||||
|
||||
|
||||
#define INSTALL_HEADERS \
|
||||
aiBehaviors.h \
|
||||
aiCharacter.h \
|
||||
aiGlobals.h \
|
||||
aiNode.h \
|
||||
aiPathFinder.h \
|
||||
aiWorld.h \
|
||||
arrival.h \
|
||||
config_ai.h \
|
||||
evade.h \
|
||||
flee.h \
|
||||
flock.h \
|
||||
aiGlobals.h \
|
||||
meshNode.h \
|
||||
obstacleAvoidance.h \
|
||||
pathFind.h \
|
||||
pathFollow.h \
|
||||
pursue.h \
|
||||
seek.h \
|
||||
wander.h
|
||||
|
||||
#define IGATESCAN all
|
||||
|
||||
#end lib_target
|
||||
|
1507
build/nirai/panda3d/contrib/src/ai/aiBehaviors.cxx
Normal file
1507
build/nirai/panda3d/contrib/src/ai/aiBehaviors.cxx
Normal file
File diff suppressed because it is too large
Load diff
187
build/nirai/panda3d/contrib/src/ai/aiBehaviors.h
Normal file
187
build/nirai/panda3d/contrib/src/ai/aiBehaviors.h
Normal file
|
@ -0,0 +1,187 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : aiBehaviors.cxx
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 8 Sep 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma warning (disable:4996)
|
||||
#pragma warning (disable:4005)
|
||||
#pragma warning(disable:4275)
|
||||
|
||||
#ifndef _AIBEHAVIORS_H
|
||||
#define _AIBEHAVIORS_H
|
||||
|
||||
#include "aiGlobals.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Class : AIBehaviors
|
||||
// Description : This class implements all the steering behaviors of the AI framework, such as
|
||||
// seek, flee, pursue, evade, wander and flock. Each steering behavior has a weight which is used when more than
|
||||
// one type of steering behavior is acting on the same ai character. The weight decides the contribution of each
|
||||
// type of steering behavior. The AICharacter class has a handle to an object of this class and this allows to
|
||||
// invoke the steering behaviors via the AICharacter. This class also provides functionality such as pausing, resuming
|
||||
// and removing the AI behaviors of an AI character at anytime.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AICharacter;
|
||||
class Seek;
|
||||
class Flee;
|
||||
class Pursue;
|
||||
class Evade;
|
||||
class Arrival;
|
||||
class Flock;
|
||||
class Wander;
|
||||
class PathFollow;
|
||||
class PathFind;
|
||||
class ObstacleAvoidance;
|
||||
|
||||
typedef list<Flee, allocator<Flee> > ListFlee;
|
||||
typedef list<Evade, allocator<Evade> > ListEvade;
|
||||
|
||||
class EXPCL_PANDAAI AIBehaviors {
|
||||
|
||||
public:
|
||||
enum _behavior_type {
|
||||
_none = 0x00000,
|
||||
_seek = 0x00002,
|
||||
_flee = 0x00004,
|
||||
_flee_activate = 0x00100,
|
||||
_arrival = 0x00008,
|
||||
_arrival_activate = 0x01000,
|
||||
_wander = 0x00010,
|
||||
_pursue = 0x00040,
|
||||
_evade = 0x00080,
|
||||
_evade_activate = 0x00800,
|
||||
_flock = 0x00200,
|
||||
_flock_activate = 0x00400,
|
||||
_obstacle_avoidance = 0x02000,
|
||||
_obstacle_avoidance_activate = 0x04000
|
||||
};
|
||||
|
||||
AICharacter *_ai_char;
|
||||
Flock *_flock_group;
|
||||
|
||||
int _behaviors_flags;
|
||||
LVecBase3 _steering_force;
|
||||
|
||||
Seek *_seek_obj;
|
||||
LVecBase3 _seek_force;
|
||||
|
||||
Flee *_flee_obj;
|
||||
LVecBase3 _flee_force;
|
||||
|
||||
//! This list is used if the ai character needs to flee from multiple onjects.
|
||||
ListFlee _flee_list;
|
||||
ListFlee::iterator _flee_itr;
|
||||
|
||||
Pursue *_pursue_obj;
|
||||
LVecBase3 _pursue_force;
|
||||
|
||||
Evade *_evade_obj;
|
||||
LVecBase3 _evade_force;
|
||||
|
||||
//! This list is used if the ai character needs to evade from multiple onjects.
|
||||
ListEvade _evade_list;
|
||||
ListEvade::iterator _evade_itr;
|
||||
|
||||
Arrival *_arrival_obj;
|
||||
LVecBase3 _arrival_force;
|
||||
|
||||
//! Since Flock is a collective behavior the variables are declared within the AIBehaviors class.
|
||||
float _flock_weight;
|
||||
LVecBase3 _flock_force;
|
||||
bool _flock_done;
|
||||
|
||||
Wander * _wander_obj;
|
||||
LVecBase3 _wander_force;
|
||||
|
||||
ObstacleAvoidance *_obstacle_avoidance_obj;
|
||||
LVecBase3 _obstacle_avoidance_force;
|
||||
|
||||
PathFollow *_path_follow_obj;
|
||||
|
||||
PathFind *_path_find_obj;
|
||||
|
||||
bool _conflict, _previous_conflict;
|
||||
|
||||
AIBehaviors();
|
||||
~AIBehaviors();
|
||||
|
||||
bool is_on(_behavior_type bt);
|
||||
bool is_on(string ai_type); // special cases for pathfollow and pathfinding
|
||||
bool is_off(_behavior_type bt);
|
||||
bool is_off(string ai_type); // special cases for pathfollow and pathfinding
|
||||
void turn_on(string ai_type);
|
||||
void turn_off(string ai_type);
|
||||
|
||||
bool is_conflict();
|
||||
|
||||
void accumulate_force(string force_type, LVecBase3 force);
|
||||
LVecBase3 calculate_prioritized();
|
||||
|
||||
void flock_activate();
|
||||
LVecBase3 do_flock();
|
||||
|
||||
int char_to_int(string ai_type);
|
||||
|
||||
PUBLISHED:
|
||||
void seek(NodePath target_object, float seek_wt = 1.0);
|
||||
void seek(LVecBase3 pos, float seek_wt = 1.0);
|
||||
|
||||
void flee(NodePath target_object, double panic_distance = 10.0, double relax_distance = 10.0, float flee_wt = 1.0);
|
||||
void flee(LVecBase3 pos, double panic_distance = 10.0, double relax_distance = 10.0, float flee_wt = 1.0);
|
||||
|
||||
void pursue(NodePath target_object, float pursue_wt = 1.0);
|
||||
|
||||
void evade(NodePath target_object, double panic_distance = 10.0, double relax_distance = 10.0, float evade_wt = 1.0);
|
||||
|
||||
void arrival(double distance = 10.0);
|
||||
|
||||
void flock(float flock_wt);
|
||||
|
||||
void wander(double wander_radius = 5.0, int flag =0, double aoe = 0.0, float wander_weight = 1.0);
|
||||
|
||||
void obstacle_avoidance(float feeler_length = 1.0);
|
||||
|
||||
void path_follow(float follow_wt);
|
||||
void add_to_path(LVecBase3 pos);
|
||||
void start_follow(string type = "normal");
|
||||
|
||||
// should have different function names.
|
||||
void init_path_find(const char* navmesh_filename);
|
||||
void path_find_to(LVecBase3 pos, string type = "normal");
|
||||
void path_find_to(NodePath target, string type = "normal");
|
||||
void add_static_obstacle(NodePath obstacle);
|
||||
void add_dynamic_obstacle(NodePath obstacle);
|
||||
//
|
||||
|
||||
void remove_ai(string ai_type);
|
||||
void pause_ai(string ai_type);
|
||||
void resume_ai(string ai_type);
|
||||
|
||||
string behavior_status(string ai_type);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
124
build/nirai/panda3d/contrib/src/ai/aiCharacter.cxx
Normal file
124
build/nirai/panda3d/contrib/src/ai/aiCharacter.cxx
Normal file
|
@ -0,0 +1,124 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : aiCharacter.cxx
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 8 Sep 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "aiCharacter.h"
|
||||
|
||||
AICharacter::AICharacter(string model_name, NodePath model_np, double mass, double movt_force, double max_force) {
|
||||
_name = model_name;
|
||||
_ai_char_np = model_np;
|
||||
|
||||
_mass = mass;
|
||||
_max_force = max_force;
|
||||
_movt_force = movt_force;
|
||||
|
||||
_velocity = LVecBase3(0.0, 0.0, 0.0);
|
||||
_steering_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
|
||||
_steering = new AIBehaviors();
|
||||
_steering->_ai_char = this;
|
||||
|
||||
_pf_guide = false;
|
||||
}
|
||||
|
||||
AICharacter::~AICharacter() {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : update
|
||||
// Description : Each character's update will update its ai and physics
|
||||
// based on his resultant steering force.
|
||||
// This also makes the character look at the direction of the force.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
void AICharacter::
|
||||
update() {
|
||||
if (!_steering->is_off(_steering->_none)) {
|
||||
LVecBase3 old_pos = _ai_char_np.get_pos();
|
||||
LVecBase3 steering_force = _steering->calculate_prioritized();
|
||||
LVecBase3 acceleration = steering_force / _mass;
|
||||
|
||||
_velocity = acceleration;
|
||||
|
||||
LVecBase3 direction = _steering->_steering_force;
|
||||
direction.normalize();
|
||||
|
||||
_ai_char_np.set_pos(old_pos + _velocity) ;
|
||||
|
||||
if (steering_force.length() > 0) {
|
||||
_ai_char_np.look_at(old_pos + (direction * 5));
|
||||
_ai_char_np.set_h(_ai_char_np.get_h() + 180);
|
||||
_ai_char_np.set_p(-_ai_char_np.get_p());
|
||||
_ai_char_np.set_r(-_ai_char_np.get_r());
|
||||
}
|
||||
} else {
|
||||
_steering->_steering_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
_steering->_seek_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
_steering->_flee_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
_steering->_pursue_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
_steering->_evade_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
_steering->_arrival_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
_steering->_flock_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
_steering->_wander_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
LVecBase3 AICharacter::get_velocity() {
|
||||
return _velocity;
|
||||
}
|
||||
|
||||
void AICharacter::set_velocity(LVecBase3 velocity) {
|
||||
_velocity = velocity;
|
||||
}
|
||||
|
||||
double AICharacter::get_mass() {
|
||||
return _mass;
|
||||
}
|
||||
|
||||
void AICharacter::set_mass(double m) {
|
||||
_mass = m;
|
||||
}
|
||||
|
||||
double AICharacter::get_max_force() {
|
||||
return _max_force;
|
||||
}
|
||||
|
||||
void AICharacter::set_max_force(double max_force) {
|
||||
_max_force = max_force;
|
||||
}
|
||||
|
||||
NodePath AICharacter::get_node_path() {
|
||||
return _ai_char_np;
|
||||
}
|
||||
|
||||
void AICharacter::set_node_path(NodePath np) {
|
||||
_ai_char_np = np;
|
||||
}
|
||||
|
||||
AIBehaviors * AICharacter::get_ai_behaviors() {
|
||||
return _steering;
|
||||
}
|
||||
|
||||
void AICharacter::set_char_render(NodePath render) {
|
||||
_window_render = render;
|
||||
}
|
||||
|
||||
NodePath AICharacter::get_char_render() {
|
||||
return _window_render;
|
||||
}
|
||||
|
||||
void AICharacter::set_pf_guide(bool pf_guide) {
|
||||
_pf_guide = pf_guide;
|
||||
}
|
79
build/nirai/panda3d/contrib/src/ai/aiCharacter.h
Normal file
79
build/nirai/panda3d/contrib/src/ai/aiCharacter.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : aiCharacter.h
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 8 Sep 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma warning (disable:4996)
|
||||
#pragma warning (disable:4005)
|
||||
#pragma warning(disable:4275)
|
||||
|
||||
|
||||
#ifndef _AICHARACTER_H
|
||||
#define _AICHARACTER_H
|
||||
|
||||
#include "aiBehaviors.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Class : AICharacter
|
||||
// Description : This class is used for creating the ai characters. It assigns both physics and ai
|
||||
// attributes to the character. It also has an update function which updates the physics and ai
|
||||
// of the character. This update function is called by the AIWorld update.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AIBehaviors;
|
||||
class AIWorld;
|
||||
|
||||
class EXPCL_PANDAAI AICharacter {
|
||||
public:
|
||||
double _mass;
|
||||
double _max_force;
|
||||
LVecBase3 _velocity;
|
||||
LVecBase3 _steering_force;
|
||||
string _name;
|
||||
double _movt_force;
|
||||
unsigned int _ai_char_flock_id;
|
||||
AIWorld *_world;
|
||||
AIBehaviors *_steering;
|
||||
NodePath _window_render;
|
||||
NodePath _ai_char_np;
|
||||
bool _pf_guide;
|
||||
|
||||
void update();
|
||||
void set_velocity(LVecBase3 vel);
|
||||
void set_char_render(NodePath render);
|
||||
NodePath get_char_render();
|
||||
|
||||
PUBLISHED:
|
||||
double get_mass();
|
||||
void set_mass(double m);
|
||||
|
||||
LVecBase3 get_velocity();
|
||||
|
||||
double get_max_force();
|
||||
void set_max_force(double max_force);
|
||||
|
||||
NodePath get_node_path();
|
||||
void set_node_path(NodePath np);
|
||||
|
||||
AIBehaviors * get_ai_behaviors();
|
||||
|
||||
// This function is used to enable or disable the guides for path finding.
|
||||
void set_pf_guide(bool pf_guide);
|
||||
|
||||
AICharacter(string model_name, NodePath model_np, double mass, double movt_force, double max_force);
|
||||
~AICharacter();
|
||||
};
|
||||
|
||||
#endif
|
35
build/nirai/panda3d/contrib/src/ai/aiGlobals.h
Normal file
35
build/nirai/panda3d/contrib/src/ai/aiGlobals.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : aiGlobals.h
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date: 8 Sep 09
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma warning (disable:4996)
|
||||
#pragma warning (disable:4005)
|
||||
#pragma warning(disable:4275)
|
||||
|
||||
#ifndef _AI_GLOBALS_H
|
||||
#define _AI_GLOBALS_H
|
||||
|
||||
#include "config_ai.h"
|
||||
#include "pandaFramework.h"
|
||||
#include "textNode.h"
|
||||
#include "pandaSystem.h"
|
||||
|
||||
#include "lvecBase3.h"
|
||||
#include "nodePath.h"
|
||||
|
||||
#include "genericAsyncTask.h"
|
||||
#include "asyncTaskManager.h"
|
||||
|
||||
#endif
|
53
build/nirai/panda3d/contrib/src/ai/aiNode.cxx
Normal file
53
build/nirai/panda3d/contrib/src/ai/aiNode.cxx
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Filename: aiNode.cxx
|
||||
// Created by: Deepak, John, Navin (19Nov2009)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "aiNode.h"
|
||||
|
||||
AINode::AINode(int grid_x, int grid_y, LVecBase3 pos, float w, float l, float h) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
_neighbours[i] = NULL;
|
||||
}
|
||||
|
||||
_position = pos;
|
||||
_width = w;
|
||||
_length = l;
|
||||
_height = h;
|
||||
_grid_x = grid_x;
|
||||
_grid_y = grid_y;
|
||||
_status = ST_neutral;
|
||||
_type = true;
|
||||
_score = 0;
|
||||
_cost = 0;
|
||||
_heuristic = 0;
|
||||
_next = NULL;
|
||||
_prv_node = NULL;
|
||||
}
|
||||
|
||||
AINode::~AINode() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: contains
|
||||
// Description: This is a handy function which returns true if the
|
||||
// passed position is within the node's dimensions.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool AINode::contains(float x, float y) {
|
||||
if (_position.get_x() - _width / 2 <= x && _position.get_x() + _width / 2 >= x &&
|
||||
_position.get_y() - _length / 2 <= y && _position.get_y() + _length / 2 >= y) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
86
build/nirai/panda3d/contrib/src/ai/aiNode.h
Normal file
86
build/nirai/panda3d/contrib/src/ai/aiNode.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
// Filename: aiNode.h
|
||||
// Created by: Deepak, John, Navin (18Nov2009)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 AINODE_H
|
||||
#define AINODE_H
|
||||
|
||||
#include "aiGlobals.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : AINode
|
||||
// Description : This class is used to assign the nodes on the mesh.
|
||||
// It holds all the data necessary to compute A*
|
||||
// algorithm. It also maintains a lot of vital
|
||||
// information such as the neighbor nodes of each
|
||||
// node and also its position on the mesh.
|
||||
// Note: The Mesh Generator which is a standalone
|
||||
// tool makes use of this class to generate the nodes
|
||||
// on the mesh.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAAI AINode {
|
||||
public:
|
||||
// This variable specifies the node status whether open, close
|
||||
// or neutral.
|
||||
// open = belongs to _open_list.
|
||||
// close = belongs to _closed_list.
|
||||
// neutral = unexamined node.
|
||||
enum Status {
|
||||
ST_open,
|
||||
ST_close,
|
||||
ST_neutral
|
||||
};
|
||||
Status _status;
|
||||
|
||||
// This variable specifies whether the node is an obtacle or not.
|
||||
// Used for dynamic obstacle addition to the environment.
|
||||
// obstacle = false
|
||||
// navigational = true
|
||||
bool _type;
|
||||
|
||||
// The score is used to compute the traversal expense to nodes
|
||||
// when using A*.
|
||||
// _score = _cost + heuristic
|
||||
int _score;
|
||||
int _cost;
|
||||
int _heuristic;
|
||||
|
||||
// Used to trace back the path after it is generated using A*.
|
||||
AINode *_prv_node;
|
||||
|
||||
// Position of the node in the 2d grid.
|
||||
int _grid_x, _grid_y;
|
||||
|
||||
// Position of the node in 3D space.
|
||||
LVecBase3 _position;
|
||||
|
||||
// Dimensions of each face / cell on the mesh.
|
||||
// Height is given in case of expansion to a 3d mesh. Currently
|
||||
// not used.
|
||||
float _width, _length ,_height;
|
||||
AINode *_neighbours[8]; // anti-clockwise from top left corner.
|
||||
|
||||
// The _next pointer is used for traversal during mesh
|
||||
// generation from the model.
|
||||
// Note: The data in this member is discarded when mesh data
|
||||
// is written into navmesh.csv file.
|
||||
AINode *_next;
|
||||
|
||||
PUBLISHED:
|
||||
AINode(int grid_x, int grid_y, LVecBase3 pos, float w, float l, float h);
|
||||
~AINode();
|
||||
|
||||
bool contains(float x, float y);
|
||||
};
|
||||
|
||||
#endif
|
395
build/nirai/panda3d/contrib/src/ai/aiPathFinder.cxx
Normal file
395
build/nirai/panda3d/contrib/src/ai/aiPathFinder.cxx
Normal file
|
@ -0,0 +1,395 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : aiPathFinder.cxx
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 10 Nov 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "aiPathFinder.h"
|
||||
|
||||
PathFinder::PathFinder(NavMesh nav_mesh) {
|
||||
_grid = nav_mesh;
|
||||
}
|
||||
|
||||
PathFinder::~PathFinder() {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : find_path
|
||||
// Description : This function initializes the pathfinding process by accepting the
|
||||
// source and destination nodes. It then calls the generate_path().
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFinder::find_path(Node *src_node, Node *dest_node) {
|
||||
_src_node = src_node;
|
||||
_dest_node = dest_node;
|
||||
|
||||
// Add a dummy node as the first element of the open list with score = -1.
|
||||
// Inorder to implement a binary heap the index of the elements should never be 0.
|
||||
Node *_dummy_node = new Node(-1, -1, LVecBase3(0.0, 0.0, 0.0), 0, 0, 0);
|
||||
_dummy_node->_status = _dummy_node->open;
|
||||
_dummy_node->_score = -1;
|
||||
_open_list.push_back(_dummy_node);
|
||||
|
||||
// Add the source node to the open list.
|
||||
add_to_olist(_src_node);
|
||||
|
||||
// Generate the path.
|
||||
generate_path();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : generate_path
|
||||
// Description : This function performs the pathfinding process using the A* algorithm.
|
||||
// It updates the openlist and closelist.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFinder::generate_path() {
|
||||
// All the A* algorithm is implemented here.
|
||||
// The check is > 1 due to the existence of the dummy node.
|
||||
while(_open_list.size() > 1) {
|
||||
// The first element of the open list will always be the optimal node.
|
||||
// This is because the open list is a binary heap with element having the
|
||||
// smallest score at the top of the heap.
|
||||
Node* nxt_node = _open_list[1];
|
||||
|
||||
if(nxt_node->_grid_x == _dest_node->_grid_x &&
|
||||
nxt_node->_grid_y == _dest_node->_grid_y) {
|
||||
// Remove the optimal node from the top of the heap.
|
||||
remove_from_olist();
|
||||
|
||||
// add the used node to the closed list.
|
||||
add_to_clist(nxt_node);
|
||||
|
||||
// At this point the destination is reached.
|
||||
return;
|
||||
}
|
||||
else {
|
||||
identify_neighbors(nxt_node);
|
||||
|
||||
// add the used node to the closed list.
|
||||
add_to_clist(nxt_node);
|
||||
}
|
||||
}
|
||||
cout<<"DESTINATION NOT REACHABLE MATE!"<<endl;
|
||||
_closed_list.clear();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : identify_neighbors
|
||||
// Description : This function traverses through the 8 neigbors of the parent node and
|
||||
// then adds the neighbors to the _open_list based on A* criteria.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFinder::identify_neighbors(Node *parent_node) {
|
||||
// Remove the parent node from the open_list so that it is not considered
|
||||
// while adding new nodes to the open list heap.
|
||||
remove_from_olist();
|
||||
for(int i = 0; i < 8; ++i) {
|
||||
if(parent_node->_neighbours[i] != NULL) {
|
||||
if(parent_node->_neighbours[i]->_status == parent_node->_neighbours[i]->neutral
|
||||
&& parent_node->_neighbours[i]->_type == true) {
|
||||
// Link the neighbor to the parent node.
|
||||
parent_node->_neighbours[i]->_prv_node = parent_node;
|
||||
// Calculate and update the score for the node.
|
||||
calc_node_score(parent_node->_neighbours[i]);
|
||||
// Add the neighbor to the open list.
|
||||
add_to_olist(parent_node->_neighbours[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : calc_node_score
|
||||
// Description : This function calculates the score of each node.
|
||||
// Score = Cost + Heuristics.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFinder::calc_node_score(Node *nd) {
|
||||
nd->_cost = calc_cost_frm_src(nd);
|
||||
nd->_heuristic = calc_heuristic(nd);
|
||||
nd->_score = nd->_cost + nd->_heuristic;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : calc_cost_frm_src
|
||||
// Description : This function calculates the cost of each node by finding out
|
||||
// the number of node traversals required to reach the source node.
|
||||
// Diagonal traversals have cost = 14.
|
||||
// Horizontal / Vertical traversals have cost = 10.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int PathFinder::calc_cost_frm_src(Node *nd) {
|
||||
int cost = 0;
|
||||
Node *start_node = nd;
|
||||
while(start_node->_prv_node != _src_node) {
|
||||
if(is_diagonal_node(start_node)) {
|
||||
cost += 14;
|
||||
}
|
||||
else {
|
||||
cost += 10;
|
||||
}
|
||||
start_node = start_node->_prv_node;
|
||||
}
|
||||
// Add the cost of traversal to the source node also.
|
||||
if(is_diagonal_node(start_node)) {
|
||||
cost += 14;
|
||||
}
|
||||
else {
|
||||
cost += 10;
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : calc_heuristic
|
||||
// Description : This function calculates the heuristic of the nodes using Manhattan method.
|
||||
// All it does is predict the number of node traversals required to reach the target node.
|
||||
// No diagonal traversals are allowed in this technique.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int PathFinder::calc_heuristic(Node *nd) {
|
||||
int row_diff = abs(_dest_node->_grid_x - nd->_grid_x);
|
||||
int col_diff = abs(_dest_node->_grid_y - nd->_grid_y);
|
||||
|
||||
int heuristic = 10 * (row_diff + col_diff);
|
||||
return heuristic;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : is_diagonal_node
|
||||
// Description : This function checks if the traversal from a node is diagonal.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool PathFinder::is_diagonal_node(Node *nd) {
|
||||
// Calculate the row and column differences between child and parent nodes.
|
||||
float row_diff = nd->_grid_x - nd->_prv_node->_grid_x;
|
||||
float col_diff = nd->_grid_y - nd->_prv_node->_grid_y;
|
||||
|
||||
// Check if the relationship between child and parent node is diagonal.
|
||||
if(row_diff == 0 || col_diff == 0) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : add_to_olist
|
||||
// Description : This function adds a node to the open list heap.
|
||||
// A binay heap is maintained to improve the search.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void PathFinder::add_to_olist(Node *nd) {
|
||||
// Variables required to search the binary heap.
|
||||
Node *child_node, *parent_node;
|
||||
int child_idx, parent_idx;
|
||||
|
||||
// Set the status as open.
|
||||
nd->_status = nd->open;
|
||||
// Add the node to the open list.
|
||||
_open_list.push_back(nd);
|
||||
|
||||
// Find the parent and child nodes and create temporary nodes out of them.
|
||||
// In a binary heap the children of a parent node are always i*2 and i*2 + 1,
|
||||
// where i is the index of the parent node in the heap. And hence, the parent
|
||||
// of a node can be easily found out by dividing by 2 and rounding it.
|
||||
child_idx = _open_list.size() - 1;
|
||||
parent_idx = child_idx / 2;
|
||||
child_node = _open_list[child_idx];
|
||||
parent_node = _open_list[parent_idx];
|
||||
|
||||
// Keep traversing the heap until the lowest element in the list is bubbled
|
||||
// to the top of the heap.
|
||||
while(_open_list[child_idx]->_score <= _open_list[parent_idx]->_score) {
|
||||
// Swap the parent node and the child node.
|
||||
_open_list[parent_idx] = child_node;
|
||||
_open_list[child_idx] = parent_node;
|
||||
|
||||
// Update the new child and parent indices.
|
||||
child_idx = parent_idx;
|
||||
parent_idx = child_idx / 2;
|
||||
|
||||
// Update the new child and parent nodes.
|
||||
child_node = _open_list[child_idx];
|
||||
parent_node = _open_list[parent_idx];
|
||||
}
|
||||
|
||||
// At this point the Node with the smallest score will be at the top of the heap.
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : remove_from_olist
|
||||
// Description : This function removes a node from the open list.
|
||||
// During the removal the binary heap is maintained.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFinder::remove_from_olist() {
|
||||
// Variables for maintaining the binary heap.
|
||||
Node *child_node, *child_node_1, *child_node_2;
|
||||
int child_idx, child_idx_1, child_idx_2;
|
||||
|
||||
// Remove the Node at index 1 from the open list binary heap.
|
||||
// Note: Node at index 0 of open list is a dummy node.
|
||||
_open_list.erase(_open_list.begin() + 1);
|
||||
|
||||
if(_open_list.size() > 1) {
|
||||
// Store the last element in the open list to a temp_node.
|
||||
Node *temp_node = _open_list[_open_list.size() - 1];
|
||||
|
||||
// Shift the elements of the open list to the right by 1 element circularly, excluding element at 0 index.
|
||||
for(int i = _open_list.size() - 1; i > 1; --i) {
|
||||
_open_list[i] = _open_list[i - 1];
|
||||
}
|
||||
|
||||
// Assign the temp_node to 1st element in the open list.
|
||||
_open_list[1] = temp_node;
|
||||
|
||||
// Set the iterator for traversing the node from index 1 in the heap.
|
||||
unsigned int k = 1;
|
||||
|
||||
// This loop traverses down the open list till the node reaches the correct position in the binary heap.
|
||||
while(true) {
|
||||
if((k * 2 + 1) < _open_list.size()) {
|
||||
// Two children exists for the parent node.
|
||||
child_idx_1 = k * 2;
|
||||
child_idx_2 = k * 2 + 1;
|
||||
child_node_1 = _open_list[child_idx_1];
|
||||
child_node_2 = _open_list[child_idx_2];
|
||||
|
||||
if(_open_list[child_idx_1]->_score < _open_list[child_idx_2]->_score) {
|
||||
if(_open_list[k]->_score > _open_list[child_idx_1]->_score) {
|
||||
// Swap the parent node and the child node.
|
||||
_open_list[child_idx_1] = _open_list[k];
|
||||
_open_list[k] = child_node_1;
|
||||
|
||||
// Update the parent node index.
|
||||
k = child_idx_1;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(_open_list[k]->_score > _open_list[child_idx_2]->_score) {
|
||||
// Swap the parent node and the child node.
|
||||
_open_list[child_idx_2] = _open_list[k];
|
||||
_open_list[k] = child_node_2;
|
||||
|
||||
// Update the parent node index.
|
||||
k = child_idx_2;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if((k * 2) < _open_list.size()) {
|
||||
// Only one child exists for the parent node.
|
||||
child_idx = k * 2;
|
||||
child_node = _open_list[child_idx];
|
||||
|
||||
if(_open_list[k]->_score > _open_list[child_idx]->_score) {
|
||||
// Swap the parent node and the child node.
|
||||
_open_list[child_idx] = _open_list[k];
|
||||
_open_list[k] = child_node;
|
||||
|
||||
// Update the parent node index.
|
||||
k = child_idx;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No children exists.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// At this point the Node was succesfully removed and the binary heap re-arranged.
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : add_to_clist
|
||||
// Description : This function adds a node to the closed list.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFinder::add_to_clist(Node *nd) {
|
||||
// Set the status as closed.
|
||||
nd->_status = nd->close;
|
||||
// Add the node to the close list.
|
||||
_closed_list.push_back(nd);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : remove_from_clist
|
||||
// Description : This function removes a node from the closed list.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFinder::remove_from_clist(int r, int c) {
|
||||
for(unsigned int i = 0; i < _closed_list.size(); ++i) {
|
||||
if(_closed_list[i]->_grid_x == r && _closed_list[i]->_grid_y == c) {
|
||||
_closed_list.erase(_closed_list.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : find_in_mesh
|
||||
// Description : This function allows the user to pass a position and it returns the
|
||||
// corresponding node on the navigation mesh. A very useful function as
|
||||
// it allows for dynamic updation of the mesh based on position.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Node* find_in_mesh(NavMesh nav_mesh, LVecBase3 pos, int grid_size) {
|
||||
int size = grid_size;
|
||||
float x = pos[0];
|
||||
float y = pos[1];
|
||||
|
||||
for(int i = 0; i < size; ++i) {
|
||||
for(int j = 0; j < size; ++j) {
|
||||
if(nav_mesh[i][j] != NULL && nav_mesh[i][j]->contains(x, y)) {
|
||||
return(nav_mesh[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
64
build/nirai/panda3d/contrib/src/ai/aiPathFinder.h
Normal file
64
build/nirai/panda3d/contrib/src/ai/aiPathFinder.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : aiPathFinder.h
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 10 Nov 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 _PATHFINDER_H
|
||||
#define _PATHFINDER_H
|
||||
|
||||
#include "meshNode.h"
|
||||
#include "cmath.h"
|
||||
#include "lineSegs.h"
|
||||
|
||||
typedef vector<Node *> NodeArray;
|
||||
typedef vector<NodeArray> NavMesh;
|
||||
|
||||
Node* find_in_mesh(NavMesh nav_mesh, LVecBase3 pos, int grid_size);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Class : PathFinder
|
||||
// Description : This class implements pathfinding using A* algorithm. It also uses a Binary Heap search to
|
||||
// search the open list. The heuristics are calculated using the manhattan method.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class EXPCL_PANDAAI PathFinder {
|
||||
public:
|
||||
Node *_src_node;
|
||||
Node *_dest_node;
|
||||
vector<Node*> _open_list;
|
||||
vector<Node*> _closed_list;
|
||||
|
||||
NavMesh _grid;
|
||||
|
||||
void identify_neighbors(Node *nd);
|
||||
int calc_cost_frm_src(Node *nd);
|
||||
int calc_heuristic(Node *nd);
|
||||
void calc_node_score(Node *nd);
|
||||
bool is_diagonal_node(Node *nd);
|
||||
|
||||
void add_to_olist(Node *nd);
|
||||
void remove_from_olist();
|
||||
|
||||
void add_to_clist(Node *nd);
|
||||
void remove_from_clist(int r, int c);
|
||||
|
||||
void generate_path();
|
||||
void find_path(Node *src_node, Node *dest_node);
|
||||
PathFinder(NavMesh nav_mesh);
|
||||
~PathFinder();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
280
build/nirai/panda3d/contrib/src/ai/aiWorld.cxx
Normal file
280
build/nirai/panda3d/contrib/src/ai/aiWorld.cxx
Normal file
|
@ -0,0 +1,280 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : aiWorld.cxx
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 8 Sep 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "aiWorld.h"
|
||||
|
||||
AIWorld::AIWorld(NodePath render) {
|
||||
_ai_char_pool = new AICharPool();
|
||||
_render = render;
|
||||
}
|
||||
|
||||
AIWorld::~AIWorld() {
|
||||
}
|
||||
|
||||
void AIWorld::add_ai_char(AICharacter *ai_char) {
|
||||
_ai_char_pool->append(ai_char);
|
||||
ai_char->_window_render = _render;
|
||||
ai_char->_world = this;
|
||||
}
|
||||
|
||||
void AIWorld::remove_ai_char(string name) {
|
||||
_ai_char_pool->del(name);
|
||||
remove_ai_char_from_flock(name);
|
||||
}
|
||||
|
||||
void AIWorld::remove_ai_char_from_flock(string name) {
|
||||
AICharPool::node *ai_pool;
|
||||
ai_pool = _ai_char_pool->_head;
|
||||
while((ai_pool) != NULL) {
|
||||
for(unsigned int i = 0; i < _flock_pool.size(); ++i) {
|
||||
if(ai_pool->_ai_char->_ai_char_flock_id == _flock_pool[i]->get_id()) {
|
||||
for(unsigned int j = 0; j<_flock_pool[i]->_ai_char_list.size(); ++j) {
|
||||
if(_flock_pool[i]->_ai_char_list[j]->_name == name) {
|
||||
_flock_pool[i]->_ai_char_list.erase(_flock_pool[i]->_ai_char_list.begin() + j);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ai_pool = ai_pool->_next;
|
||||
}
|
||||
}
|
||||
|
||||
void AIWorld::print_list() {
|
||||
_ai_char_pool->print_list();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Function : update
|
||||
// Description : The AIWorld update function calls the update function of all the
|
||||
// AI characters which have been added to the AIWorld.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AIWorld::update() {
|
||||
AICharPool::node *ai_pool;
|
||||
ai_pool = _ai_char_pool->_head;
|
||||
|
||||
while((ai_pool)!=NULL) {
|
||||
ai_pool->_ai_char->update();
|
||||
ai_pool = ai_pool->_next;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : add_flock
|
||||
// Description : This function adds all the AI characters in the Flock object to
|
||||
// the AICharPool. This function allows adding the AI characetrs as
|
||||
// part of a flock.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AIWorld::add_flock(Flock *flock) {
|
||||
// Add all the ai_characters in the flock to the AIWorld.
|
||||
for(unsigned int i = 0; i < flock->_ai_char_list.size(); ++i) {
|
||||
this->add_ai_char(flock->_ai_char_list[i]);
|
||||
}
|
||||
// Add the flock to the flock pool.
|
||||
_flock_pool.push_back(flock);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : get_flock
|
||||
// Description : This function returns a handle to the Flock whose id is passed.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Flock AIWorld::get_flock(unsigned int flock_id) {
|
||||
for(unsigned int i=0; i < _flock_pool.size(); ++i) {
|
||||
if(_flock_pool[i]->get_id() == flock_id) {
|
||||
return *_flock_pool[i];
|
||||
}
|
||||
}
|
||||
Flock *null_flock = NULL;
|
||||
return *null_flock;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : remove_flock
|
||||
// Description : This function removes the flock behavior completely.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AIWorld::remove_flock(unsigned int flock_id) {
|
||||
for(unsigned int i = 0; i < _flock_pool.size(); ++i) {
|
||||
if(_flock_pool[i]->get_id() == flock_id) {
|
||||
for(unsigned int j = 0; j < _flock_pool[i]->_ai_char_list.size(); ++j) {
|
||||
_flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_off("flock_activate");
|
||||
_flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_off("flock");
|
||||
_flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->_flock_group = NULL;
|
||||
}
|
||||
_flock_pool.erase(_flock_pool.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : flock_off
|
||||
// Description : This function turns off the flock behavior temporarily. Similar to
|
||||
// pausing the behavior.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AIWorld::flock_off(unsigned int flock_id) {
|
||||
for(unsigned int i = 0; i < _flock_pool.size(); ++i) {
|
||||
if(_flock_pool[i]->get_id() == flock_id) {
|
||||
for(unsigned int j = 0; j < _flock_pool[i]->_ai_char_list.size(); ++j) {
|
||||
_flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_off("flock_activate");
|
||||
_flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_off("flock");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : flock_on
|
||||
// Description : This function turns on the flock behavior.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AIWorld::flock_on(unsigned int flock_id) {
|
||||
for(unsigned int i = 0; i < _flock_pool.size(); ++i) {
|
||||
if(_flock_pool[i]->get_id() == flock_id) {
|
||||
for(unsigned int j = 0; j < _flock_pool[i]->_ai_char_list.size(); ++j) {
|
||||
_flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_on("flock_activate");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AICharPool::AICharPool() {
|
||||
_head = NULL;
|
||||
}
|
||||
|
||||
AICharPool::~AICharPool() {
|
||||
}
|
||||
|
||||
void AICharPool::append(AICharacter *ai_ch) {
|
||||
node *q;
|
||||
node *t;
|
||||
|
||||
if(_head == NULL) {
|
||||
q = new node();
|
||||
q->_ai_char = ai_ch;
|
||||
q->_next = NULL;
|
||||
_head = q;
|
||||
}
|
||||
else {
|
||||
q = _head;
|
||||
while( q->_next != NULL) {
|
||||
q = q->_next;
|
||||
}
|
||||
|
||||
t = new node();
|
||||
t->_ai_char = ai_ch;
|
||||
t->_next = NULL;
|
||||
q->_next = t;
|
||||
}
|
||||
}
|
||||
|
||||
void AICharPool::del(string name) {
|
||||
node *q;
|
||||
node *r;
|
||||
q = _head;
|
||||
|
||||
if(_head==NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only one node in the linked list
|
||||
if(q->_next == NULL) {
|
||||
if(q->_ai_char->_name == name) {
|
||||
_head = NULL;
|
||||
delete q;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
r = q;
|
||||
while( q != NULL) {
|
||||
if( q->_ai_char->_name == name) {
|
||||
// Special case
|
||||
if(q == _head) {
|
||||
_head = q->_next;
|
||||
delete q;
|
||||
return;
|
||||
}
|
||||
|
||||
r->_next = q->_next;
|
||||
delete q;
|
||||
return;
|
||||
}
|
||||
r = q;
|
||||
q = q->_next;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : print_list
|
||||
// Description : This function prints the ai characters in the AICharPool. Used for
|
||||
// debugging purposes.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AICharPool::print_list() {
|
||||
node* q;
|
||||
q = _head;
|
||||
while(q != NULL) {
|
||||
cout<<q->_ai_char->_name<<endl;
|
||||
q = q->_next;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : add_obstacle
|
||||
// Description : This function adds the nodepath as an obstacle that is needed
|
||||
// by the obstacle avoidance behavior.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AIWorld::add_obstacle(NodePath obstacle) {
|
||||
_obstacles.push_back(obstacle);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : remove_obstacle
|
||||
// Description : This function removes the nodepath from the obstacles list that is needed
|
||||
// by the obstacle avoidance behavior.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AIWorld::remove_obstacle(NodePath obstacle) {
|
||||
for(unsigned int i = 0; i <= _obstacles.size(); ++i) {
|
||||
if(_obstacles[i] == obstacle) {
|
||||
_obstacles.erase(_obstacles.begin() + i);
|
||||
}
|
||||
}
|
||||
}
|
108
build/nirai/panda3d/contrib/src/ai/aiWorld.h
Normal file
108
build/nirai/panda3d/contrib/src/ai/aiWorld.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : aiWorld.h
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 8 Sep 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma warning (disable:4996)
|
||||
#pragma warning (disable:4005)
|
||||
#pragma warning(disable:4275)
|
||||
|
||||
|
||||
#ifndef _AIWORLD_H
|
||||
#define _AIWORLD_H
|
||||
|
||||
#include "aiGlobals.h"
|
||||
#include "aiCharacter.h"
|
||||
#include "flock.h"
|
||||
|
||||
class AICharacter;
|
||||
class Flock;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Class : AICharPool
|
||||
// Description : This class implements a linked list of AI Characters allowing
|
||||
// the user to add and delete characters from the linked list.
|
||||
// This will be used in the AIWorld class.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class EXPCL_PANDAAI AICharPool {
|
||||
public:
|
||||
struct node {
|
||||
AICharacter * _ai_char;
|
||||
node * _next;
|
||||
} ;
|
||||
|
||||
node* _head;
|
||||
AICharPool();
|
||||
~AICharPool();
|
||||
void append(AICharacter *ai_ch);
|
||||
void del(string name);
|
||||
void print_list();
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Class : AIWorld
|
||||
// Description : A class that implements the virtual AI world which keeps track
|
||||
// of the AI characters active at any given time. It contains a linked
|
||||
// list of AI characters, obstactle data and unique name for each
|
||||
// character. It also updates each characters state. The AI characters
|
||||
// can also be added to the world as flocks.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class EXPCL_PANDAAI AIWorld {
|
||||
private:
|
||||
AICharPool * _ai_char_pool;
|
||||
NodePath _render;
|
||||
public:
|
||||
vector<NodePath> _obstacles;
|
||||
typedef std::vector<Flock*> FlockPool;
|
||||
FlockPool _flock_pool;
|
||||
void remove_ai_char_from_flock(string name);
|
||||
|
||||
PUBLISHED:
|
||||
AIWorld(NodePath render);
|
||||
~AIWorld();
|
||||
|
||||
void add_ai_char(AICharacter *ai_ch);
|
||||
void remove_ai_char(string name);
|
||||
|
||||
void add_flock(Flock *flock);
|
||||
void flock_off(unsigned int flock_id);
|
||||
void flock_on(unsigned int flock_id);
|
||||
void remove_flock(unsigned int flock_id);
|
||||
Flock get_flock(unsigned int flock_id);
|
||||
|
||||
void add_obstacle(NodePath obstacle);
|
||||
void remove_obstacle(NodePath obstacle);
|
||||
|
||||
void print_list();
|
||||
void update();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
122
build/nirai/panda3d/contrib/src/ai/arrival.cxx
Normal file
122
build/nirai/panda3d/contrib/src/ai/arrival.cxx
Normal file
|
@ -0,0 +1,122 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : arrival.cxx
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 24 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "arrival.h"
|
||||
|
||||
Arrival::Arrival(AICharacter *ai_ch, double distance) {
|
||||
_ai_char = ai_ch;
|
||||
|
||||
_arrival_distance = distance;
|
||||
_arrival_done = false;
|
||||
}
|
||||
|
||||
Arrival::~Arrival() {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : do_arrival
|
||||
// Description : This function performs the arrival and returns an arrival force which is used
|
||||
// in the calculate_prioritized function.
|
||||
// In case the steering force = 0, it resets to arrival_activate.
|
||||
// The arrival behavior works only when seek or pursue is active.
|
||||
// This function is not to be used by the user.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LVecBase3 Arrival::do_arrival() {
|
||||
LVecBase3 direction_to_target;
|
||||
double distance;
|
||||
|
||||
if(_arrival_type) {
|
||||
direction_to_target = _ai_char->get_ai_behaviors()->_pursue_obj->_pursue_target.get_pos(_ai_char->_window_render) - _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
|
||||
}
|
||||
else {
|
||||
direction_to_target = _ai_char->get_ai_behaviors()->_seek_obj->_seek_position - _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
|
||||
}
|
||||
distance = direction_to_target.length();
|
||||
|
||||
_arrival_direction = direction_to_target;
|
||||
_arrival_direction.normalize();
|
||||
|
||||
if(int(distance) == 0) {
|
||||
_ai_char->_steering->_steering_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
_ai_char->_steering->_arrival_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
|
||||
if(_ai_char->_steering->_seek_obj != NULL) {
|
||||
_ai_char->_steering->turn_off("arrival");
|
||||
_ai_char->_steering->turn_on("arrival_activate");
|
||||
}
|
||||
_arrival_done = true;
|
||||
return(LVecBase3(0.0, 0.0, 0.0));
|
||||
}
|
||||
else {
|
||||
_arrival_done = false;
|
||||
}
|
||||
|
||||
double u = _ai_char->get_velocity().length();
|
||||
LVecBase3 desired_force = ((u * u) / (2 * distance)) * _ai_char->get_mass();
|
||||
|
||||
if(_ai_char->_steering->_seek_obj != NULL) {
|
||||
return(desired_force);
|
||||
}
|
||||
|
||||
if(_ai_char->_steering->_pursue_obj != NULL) {
|
||||
|
||||
if(distance > _arrival_distance) {
|
||||
_ai_char->_steering->turn_off("arrival");
|
||||
_ai_char->_steering->turn_on("arrival_activate");
|
||||
_ai_char->_steering->resume_ai("pursue");
|
||||
}
|
||||
|
||||
return(desired_force);
|
||||
}
|
||||
|
||||
cout<<"Arrival works only with seek and pursue"<<endl;
|
||||
return(LVecBase3(0.0, 0.0, 0.0));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : arrival_activate
|
||||
// Description : This function checks for whether the target is within the arrival distance.
|
||||
// When this is true, it calls the do_arrival function and sets the arrival direction.
|
||||
// This function is not to be used by the user.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Arrival::arrival_activate() {
|
||||
LVecBase3 dirn;
|
||||
if(_arrival_type) {
|
||||
dirn = (_ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _ai_char->get_ai_behaviors()->_pursue_obj->_pursue_target.get_pos(_ai_char->_window_render));
|
||||
}
|
||||
else {
|
||||
dirn = (_ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _ai_char->get_ai_behaviors()->_seek_obj->_seek_position);
|
||||
}
|
||||
double distance = dirn.length();
|
||||
|
||||
if(distance < _arrival_distance && _ai_char->_steering->_steering_force.length() > 0) {
|
||||
_ai_char->_steering->turn_off("arrival_activate");
|
||||
_ai_char->_steering->turn_on("arrival");
|
||||
|
||||
if(_ai_char->_steering->is_on(_ai_char->_steering->_seek)) {
|
||||
_ai_char->_steering->turn_off("seek");
|
||||
}
|
||||
|
||||
if(_ai_char->_steering->is_on(_ai_char->_steering->_pursue)) {
|
||||
_ai_char->_steering->pause_ai("pursue");
|
||||
}
|
||||
}
|
||||
}
|
46
build/nirai/panda3d/contrib/src/ai/arrival.h
Normal file
46
build/nirai/panda3d/contrib/src/ai/arrival.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : arrival.h
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 24 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 _ARRIVAL_H
|
||||
#define _ARRIVAL_H
|
||||
|
||||
#include "aiGlobals.h"
|
||||
#include "aiCharacter.h"
|
||||
|
||||
class AICharacter;
|
||||
|
||||
class EXPCL_PANDAAI Arrival {
|
||||
|
||||
public:
|
||||
AICharacter *_ai_char;
|
||||
|
||||
NodePath _arrival_target;
|
||||
LVecBase3 _arrival_target_pos;
|
||||
double _arrival_distance;
|
||||
LVecBase3 _arrival_direction;
|
||||
bool _arrival_done;
|
||||
|
||||
// This flag specifies if the arrival behavior is being used with seek or pursue behavior.
|
||||
// True = used with pursue.
|
||||
// False = used with seek.
|
||||
bool _arrival_type;
|
||||
|
||||
Arrival(AICharacter *ai_ch, double distance = 10.0);
|
||||
~Arrival();
|
||||
LVecBase3 do_arrival();
|
||||
void arrival_activate();
|
||||
};
|
||||
|
||||
#endif
|
55
build/nirai/panda3d/contrib/src/ai/config_ai.cxx
Normal file
55
build/nirai/panda3d/contrib/src/ai/config_ai.cxx
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Filename: config_ai.cxx
|
||||
// Created by: Pandai (13Sep09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "config_ai.h"
|
||||
#include "aiWorld.h"
|
||||
#include "aiCharacter.h"
|
||||
#include "aiBehaviors.h"
|
||||
#include "seek.h"
|
||||
#include "flee.h"
|
||||
#include "pursue.h"
|
||||
#include "evade.h"
|
||||
#include "arrival.h"
|
||||
#include "flock.h"
|
||||
#include "wander.h"
|
||||
#include "pathFollow.h"
|
||||
#include "obstacleAvoidance.h"
|
||||
#include "pathFind.h"
|
||||
#include "aiNode.h"
|
||||
#include "aiPathFinder.h"
|
||||
#include "dconfig.h"
|
||||
|
||||
Configure(config_ai);
|
||||
NotifyCategoryDef(ai, "");
|
||||
|
||||
ConfigureFn(config_ai) {
|
||||
init_libai();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: init_libai
|
||||
// Description: Initializes the library. This must be called at
|
||||
// least once before any of the functions or classes in
|
||||
// this library can be used. Normally it will be
|
||||
// called by the static initializers and need not be
|
||||
// called explicitly, but special cases exist.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
init_libai() {
|
||||
static bool initialized = false;
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
}
|
26
build/nirai/panda3d/contrib/src/ai/config_ai.h
Normal file
26
build/nirai/panda3d/contrib/src/ai/config_ai.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
// Filename: config_ai.h
|
||||
// Created by: Pandai (13Sep09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 CONFIG_AI_H
|
||||
#define CONFIG_AI_H
|
||||
|
||||
#include "contribbase.h"
|
||||
#include "notifyCategoryProxy.h"
|
||||
|
||||
NotifyCategoryDecl(ai, EXPCL_PANDAAI, EXPTP_PANDAAI);
|
||||
|
||||
extern EXPCL_PANDAAI void init_libai();
|
||||
|
||||
#endif
|
||||
|
88
build/nirai/panda3d/contrib/src/ai/evade.cxx
Normal file
88
build/nirai/panda3d/contrib/src/ai/evade.cxx
Normal file
|
@ -0,0 +1,88 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : evade.cxx
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 24 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "evade.h"
|
||||
|
||||
Evade::Evade(AICharacter *ai_ch, NodePath target_object, double panic_distance,
|
||||
double relax_distance, float evade_wt) {
|
||||
_ai_char = ai_ch;
|
||||
|
||||
_evade_target = target_object;
|
||||
_evade_distance = panic_distance;
|
||||
_evade_relax_distance = relax_distance;
|
||||
_evade_weight = evade_wt;
|
||||
|
||||
_evade_done = true;
|
||||
_evade_activate_done = false;
|
||||
}
|
||||
|
||||
Evade::~Evade() {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : do_evade
|
||||
// Description : This function performs the evade and returns an evade force which is used
|
||||
// in the calculate_prioritized function.
|
||||
// In case the AICharacter is past the (panic + relax) distance,
|
||||
// it resets to evade_activate.
|
||||
// This function is not to be used by the user.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LVecBase3 Evade::do_evade() {
|
||||
assert(_evade_target && "evade target not assigned");
|
||||
|
||||
_evade_direction = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _evade_target.get_pos(_ai_char->_window_render);
|
||||
double distance = _evade_direction.length();
|
||||
|
||||
_evade_direction.normalize();
|
||||
LVecBase3 desired_force = _evade_direction * _ai_char->_movt_force;
|
||||
|
||||
if(distance > (_evade_distance + _evade_relax_distance)) {
|
||||
if((_ai_char->_steering->_behaviors_flags | _ai_char->_steering->_evade) == _ai_char->_steering->_evade) {
|
||||
_ai_char->_steering->_steering_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
}
|
||||
_ai_char->_steering->turn_off("evade");
|
||||
_ai_char->_steering->turn_on("evade_activate");
|
||||
_evade_done = true;
|
||||
return(LVecBase3(0.0, 0.0, 0.0));
|
||||
}
|
||||
else {
|
||||
_evade_done = false;
|
||||
return(desired_force);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : evade_activate
|
||||
// Description : This function checks for whether the target is within the panic distance.
|
||||
// When this is true, it calls the do_evade function and sets the evade direction.
|
||||
// This function is not to be used by the user.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Evade::evade_activate() {
|
||||
_evade_direction = (_ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _evade_target.get_pos(_ai_char->_window_render));
|
||||
double distance = _evade_direction.length();
|
||||
_evade_activate_done = false;
|
||||
|
||||
if(distance < _evade_distance) {
|
||||
_ai_char->_steering->turn_off("evade_activate");
|
||||
_ai_char->_steering->turn_on("evade");
|
||||
_evade_activate_done = true;
|
||||
}
|
||||
}
|
45
build/nirai/panda3d/contrib/src/ai/evade.h
Normal file
45
build/nirai/panda3d/contrib/src/ai/evade.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : evade.h
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 24 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 _EVADE_H
|
||||
#define _EVADE_H
|
||||
|
||||
#include "aiGlobals.h"
|
||||
#include "aiCharacter.h"
|
||||
|
||||
class AICharacter;
|
||||
|
||||
class EXPCL_PANDAAI Evade {
|
||||
|
||||
public:
|
||||
AICharacter *_ai_char;
|
||||
|
||||
NodePath _evade_target;
|
||||
float _evade_weight;
|
||||
LVecBase3 _evade_direction;
|
||||
double _evade_distance;
|
||||
double _evade_relax_distance;
|
||||
bool _evade_done;
|
||||
bool _evade_activate_done;
|
||||
|
||||
Evade(AICharacter *ai_ch, NodePath target_object, double panic_distance,
|
||||
double relax_distance, float evade_wt);
|
||||
|
||||
~Evade();
|
||||
LVecBase3 do_evade();
|
||||
void evade_activate();
|
||||
};
|
||||
|
||||
#endif
|
109
build/nirai/panda3d/contrib/src/ai/flee.cxx
Normal file
109
build/nirai/panda3d/contrib/src/ai/flee.cxx
Normal file
|
@ -0,0 +1,109 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : flee.cxx
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 24 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "flee.h"
|
||||
|
||||
Flee::Flee(AICharacter *ai_ch, NodePath target_object, double panic_distance,
|
||||
double relax_distance, float flee_wt){
|
||||
|
||||
_ai_char = ai_ch;
|
||||
|
||||
_flee_position = target_object.get_pos(_ai_char->_window_render);
|
||||
_flee_distance = panic_distance;
|
||||
_flee_weight = flee_wt;
|
||||
_flee_relax_distance = relax_distance;
|
||||
|
||||
_flee_done = false;
|
||||
_flee_activate_done = false;
|
||||
}
|
||||
|
||||
Flee::Flee(AICharacter *ai_ch, LVecBase3 pos, double panic_distance,
|
||||
double relax_distance, float flee_wt){
|
||||
|
||||
_ai_char = ai_ch;
|
||||
|
||||
_flee_position = pos;
|
||||
_flee_distance = panic_distance;
|
||||
_flee_weight = flee_wt;
|
||||
_flee_relax_distance = relax_distance;
|
||||
|
||||
_flee_done = false;
|
||||
_flee_activate_done = false;
|
||||
}
|
||||
|
||||
Flee::~Flee() {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : do_flee
|
||||
// Description : This function performs the flee and returns a flee force which is used
|
||||
// in the calculate_prioritized function.
|
||||
// In case the AICharacter is past the (panic + relax) distance,
|
||||
// it resets to flee_activate.
|
||||
// This function is not to be used by the user.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LVecBase3 Flee::do_flee() {
|
||||
LVecBase3 dirn;
|
||||
double distance;
|
||||
LVecBase3 desired_force;
|
||||
|
||||
dirn = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _flee_present_pos;
|
||||
distance = dirn.length();
|
||||
desired_force = _flee_direction * _ai_char->_movt_force;
|
||||
|
||||
if(distance > (_flee_distance + _flee_relax_distance)) {
|
||||
if((_ai_char->_steering->_behaviors_flags | _ai_char->_steering->_flee) == _ai_char->_steering->_flee) {
|
||||
_ai_char->_steering->_steering_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
}
|
||||
_flee_done = true;
|
||||
_ai_char->_steering->turn_off("flee");
|
||||
_ai_char->_steering->turn_on("flee_activate");
|
||||
return(LVecBase3(0.0, 0.0, 0.0));
|
||||
}
|
||||
else {
|
||||
return(desired_force);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : flee_activate
|
||||
// Description : This function checks for whether the target is within the panic distance.
|
||||
// When this is true, it calls the do_flee function and sets the flee direction.
|
||||
// This function is not to be used by the user.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Flee::flee_activate() {
|
||||
LVecBase3 dirn;
|
||||
double distance;
|
||||
|
||||
_flee_activate_done = false;
|
||||
|
||||
dirn = (_ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _flee_position);
|
||||
distance = dirn.length();
|
||||
|
||||
if(distance < _flee_distance) {
|
||||
_flee_direction = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _flee_position;
|
||||
_flee_direction.normalize();
|
||||
_flee_present_pos = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
|
||||
_ai_char->_steering->turn_off("flee_activate");
|
||||
_ai_char->_steering->turn_on("flee");
|
||||
_flee_activate_done = true;
|
||||
}
|
||||
}
|
49
build/nirai/panda3d/contrib/src/ai/flee.h
Normal file
49
build/nirai/panda3d/contrib/src/ai/flee.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : flee.h
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 24 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 _FLEE_H
|
||||
#define _FLEE_H
|
||||
|
||||
#include "aiGlobals.h"
|
||||
#include "aiCharacter.h"
|
||||
|
||||
class AICharacter;
|
||||
|
||||
class EXPCL_PANDAAI Flee {
|
||||
|
||||
public:
|
||||
AICharacter *_ai_char;
|
||||
|
||||
LVecBase3 _flee_position;
|
||||
float _flee_weight;
|
||||
LVecBase3 _flee_direction;
|
||||
double _flee_distance;
|
||||
double _flee_relax_distance;
|
||||
LVecBase3 _flee_present_pos;
|
||||
bool _flee_done;
|
||||
bool _flee_activate_done;
|
||||
|
||||
Flee(AICharacter *ai_ch, NodePath target_object, double panic_distance = 10.0,
|
||||
double relax_distance = 10.0, float flee_wt = 1.0);
|
||||
|
||||
Flee(AICharacter *ai_ch, LVecBase3 pos, double panic_distance = 10.0,
|
||||
double relax_distance = 10.0, float flee_wt = 1.0);
|
||||
|
||||
~Flee();
|
||||
LVecBase3 do_flee();
|
||||
void flee_activate();
|
||||
};
|
||||
|
||||
#endif
|
46
build/nirai/panda3d/contrib/src/ai/flock.cxx
Normal file
46
build/nirai/panda3d/contrib/src/ai/flock.cxx
Normal file
|
@ -0,0 +1,46 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : flock.cxx
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 12 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "flock.h"
|
||||
|
||||
Flock::Flock(unsigned int flock_id, double vcone_angle, double vcone_radius, unsigned int separation_wt,
|
||||
unsigned int cohesion_wt, unsigned int alignment_wt) {
|
||||
_flock_id = flock_id;
|
||||
_flock_vcone_angle = vcone_angle;
|
||||
_flock_vcone_radius = vcone_radius;
|
||||
_separation_wt = separation_wt;
|
||||
_cohesion_wt = cohesion_wt;
|
||||
_alignment_wt = alignment_wt;
|
||||
}
|
||||
|
||||
Flock::~Flock() {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : add_ai_char
|
||||
// Description : This function adds AI characters to the flock.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Flock::add_ai_char(AICharacter *ai_char) {
|
||||
ai_char->_ai_char_flock_id = _flock_id;
|
||||
ai_char->_steering->_flock_group = this;
|
||||
_ai_char_list.push_back(ai_char);
|
||||
}
|
||||
|
||||
unsigned int Flock::get_id() {
|
||||
return _flock_id;
|
||||
}
|
63
build/nirai/panda3d/contrib/src/ai/flock.h
Normal file
63
build/nirai/panda3d/contrib/src/ai/flock.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : flock.h
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 12 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 _FLOCK_H
|
||||
#define _FLOCK_H
|
||||
|
||||
#include "aiGlobals.h"
|
||||
#include "aiCharacter.h"
|
||||
|
||||
class AICharacter;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Class : Flock
|
||||
// Description : This class is used to define the flock attributes and the AI characters
|
||||
// which are part of the flock.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class EXPCL_PANDAAI Flock {
|
||||
private:
|
||||
unsigned int _flock_id;
|
||||
|
||||
public:
|
||||
// Variables which will hold the parameters of the ai character's visibilty cone.
|
||||
double _flock_vcone_angle;
|
||||
double _flock_vcone_radius;
|
||||
|
||||
// Variables to specify weights of separation, cohesion and alignment behaviors and thus
|
||||
// create variable flock behavior.
|
||||
unsigned int _separation_wt;
|
||||
unsigned int _cohesion_wt;
|
||||
unsigned int _alignment_wt;
|
||||
|
||||
// This vector will hold all the ai characters which belong to this flock.
|
||||
typedef std::vector<AICharacter*> AICharList;
|
||||
AICharList _ai_char_list;
|
||||
|
||||
PUBLISHED:
|
||||
Flock(unsigned int flock_id, double vcone_angle, double vcone_radius, unsigned int separation_wt = 2,
|
||||
unsigned int cohesion_wt = 4, unsigned int alignment_wt = 1);
|
||||
~Flock();
|
||||
|
||||
// Function to add the ai characters to _ai_char_list.
|
||||
void add_ai_char(AICharacter *ai_char);
|
||||
|
||||
// Function to access the private member flock_id.
|
||||
unsigned int get_id();
|
||||
};
|
||||
|
||||
#endif
|
43
build/nirai/panda3d/contrib/src/ai/meshNode.cxx
Normal file
43
build/nirai/panda3d/contrib/src/ai/meshNode.cxx
Normal file
|
@ -0,0 +1,43 @@
|
|||
|
||||
#include "meshNode.h"
|
||||
|
||||
Node::Node(int grid_x, int grid_y, LVecBase3 pos, float w, float l, float h) {
|
||||
for(int i = 0; i < 8; ++i) {
|
||||
_neighbours[i] = NULL;
|
||||
}
|
||||
|
||||
_position = pos;
|
||||
_width = w;
|
||||
_length = l;
|
||||
_height = h;
|
||||
_grid_x = grid_x;
|
||||
_grid_y = grid_y;
|
||||
_status = neutral;
|
||||
_type = true;
|
||||
_score = 0;
|
||||
_cost = 0;
|
||||
_heuristic = 0;
|
||||
_next = NULL;
|
||||
_prv_node = NULL;
|
||||
}
|
||||
|
||||
Node::~Node() {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : contains
|
||||
// Description : This is a handy function which returns true if the passed position is
|
||||
// within the node's dimensions.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Node::contains(float x, float y) {
|
||||
if(_position.get_x() - _width / 2 <= x && _position.get_x() + _width / 2 >= x &&
|
||||
_position.get_y() - _length / 2 <= y && _position.get_y() + _length / 2 >= y) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
67
build/nirai/panda3d/contrib/src/ai/meshNode.h
Normal file
67
build/nirai/panda3d/contrib/src/ai/meshNode.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
|
||||
#ifndef _MESHNODE_H
|
||||
#define _MESHNODE_H
|
||||
|
||||
#include "aiGlobals.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Class : Node
|
||||
// Description : This class is used to assign the nodes on the mesh. It holds all the data necessary to
|
||||
// compute A* algorithm. It also maintains a lot of vital information such as the neighbor
|
||||
// nodes of each node and also its position on the mesh.
|
||||
// Note: The Mesh Generator which is a stand alone tool makes use of this class to generate the nodes on the
|
||||
// mesh.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class EXPCL_PANDAAI Node {
|
||||
public:
|
||||
// This variable specifies whether the node is an obtacle or not.
|
||||
// Used for dynamic obstacle addition to the environment.
|
||||
// obstacle = false
|
||||
// navigational = true
|
||||
bool _type;
|
||||
|
||||
// This variable specifies the node status whether open, close or neutral.
|
||||
// open = belongs to _open_list.
|
||||
// close = belongs to _closed_list.
|
||||
// neutral = unexamined node.
|
||||
enum Status {
|
||||
open,
|
||||
close,
|
||||
neutral
|
||||
};
|
||||
Status _status;
|
||||
|
||||
// The score is used to compute the traversal expense to nodes when using A*.
|
||||
// _score = _cost + heuristic
|
||||
int _score;
|
||||
int _cost;
|
||||
int _heuristic;
|
||||
|
||||
// Used to trace back the path after it is generated using A*.
|
||||
Node *_prv_node;
|
||||
|
||||
// Position of the node in the 2d grid.
|
||||
int _grid_x, _grid_y;
|
||||
|
||||
// Position of the node in 3D space.
|
||||
LVecBase3 _position;
|
||||
|
||||
// Dimensions of each face / cell on the mesh.
|
||||
// Height is given in case of expansion to a 3d mesh. Currently not used.
|
||||
float _width, _length ,_height;
|
||||
Node *_neighbours[8]; // anti-clockwise from top left corner.
|
||||
|
||||
// The _next pointer is used for traversal during mesh generation from the model.
|
||||
// Note: The data in this member is discarded when mesh data is written into navmesh.csv file.
|
||||
Node *_next;
|
||||
|
||||
Node(int grid_x, int grid_y, LVecBase3 pos, float w, float l, float h);
|
||||
~Node();
|
||||
|
||||
bool contains(float x, float y);
|
||||
};
|
||||
|
||||
#endif
|
116
build/nirai/panda3d/contrib/src/ai/obstacleAvoidance.cxx
Normal file
116
build/nirai/panda3d/contrib/src/ai/obstacleAvoidance.cxx
Normal file
|
@ -0,0 +1,116 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : obstacleAvoidance.cxx
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 10 Nov 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "obstacleAvoidance.h"
|
||||
|
||||
ObstacleAvoidance::ObstacleAvoidance(AICharacter *ai_char, float feeler_length) {
|
||||
_ai_char = ai_char;
|
||||
_feeler = feeler_length;
|
||||
}
|
||||
|
||||
ObstacleAvoidance::~ObstacleAvoidance() {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : obstacle_detection
|
||||
// Description : This function checks if an obstacle is near to the AICharacter and
|
||||
// if an obstacle is detected returns true
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool ObstacleAvoidance::obstacle_detection() {
|
||||
// Calculate the volume of the AICharacter with respect to render
|
||||
PT(BoundingVolume) np_bounds = _ai_char->get_node_path().get_bounds();
|
||||
CPT(BoundingSphere) np_sphere = np_bounds->as_bounding_sphere();
|
||||
LVecBase3 avoidance(0.0, 0.0, 0.0);
|
||||
double distance = 0x7fff ;
|
||||
double expanded_radius;
|
||||
LVecBase3 to_obstacle;
|
||||
LVecBase3 prev_avoidance;
|
||||
for(unsigned int i = 0; i < _ai_char->_world->_obstacles.size(); ++i) {
|
||||
PT(BoundingVolume) bounds = _ai_char->_world->_obstacles[i].get_bounds();
|
||||
CPT(BoundingSphere) bsphere = bounds->as_bounding_sphere();
|
||||
LVecBase3 near_obstacle = _ai_char->_world->_obstacles[i].get_pos() - _ai_char->get_node_path().get_pos();
|
||||
// Check if it's the nearest obstacle, If so initialize as the nearest obstacle
|
||||
if((near_obstacle.length() < distance) && (_ai_char->_world->_obstacles[i].get_pos() != _ai_char->get_node_path().get_pos())) {
|
||||
_nearest_obstacle = _ai_char->_world->_obstacles[i];
|
||||
distance = near_obstacle.length();
|
||||
expanded_radius = bsphere->get_radius() + np_sphere->get_radius();
|
||||
}
|
||||
}
|
||||
LVecBase3 feeler = _feeler * _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3::forward());
|
||||
feeler.normalize();
|
||||
feeler *= (expanded_radius + np_sphere->get_radius()) ;
|
||||
to_obstacle = _nearest_obstacle.get_pos() - _ai_char->get_node_path().get_pos();
|
||||
LVector3 line_vector = _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3::forward());
|
||||
LVecBase3 project = (to_obstacle.dot(line_vector) * line_vector) / line_vector.length_squared();
|
||||
LVecBase3 perp = project - to_obstacle;
|
||||
// If the nearest obstacle will collide with our AICharacter then send obstacle detection as true
|
||||
if((_nearest_obstacle) && (perp.length() < expanded_radius - np_sphere->get_radius()) && (project.length() < feeler.length())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : obstacle_avoidance_activate
|
||||
// Description : This function activates obstacle_avoidance if a obstacle
|
||||
// is detected
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ObstacleAvoidance::obstacle_avoidance_activate() {
|
||||
if(obstacle_detection()) {
|
||||
_ai_char->_steering->turn_off("obstacle_avoidance_activate");
|
||||
_ai_char->_steering->turn_on("obstacle_avoidance");
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : do_obstacle_avoidance
|
||||
// Description : This function returns the force necessary by the AICharacter to
|
||||
// avoid the nearest obstacle detected by obstacle_detection
|
||||
// function
|
||||
// NOTE : This assumes the obstacles are spherical
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LVecBase3 ObstacleAvoidance::do_obstacle_avoidance() {
|
||||
LVecBase3 offset = _ai_char->get_node_path().get_pos() - _nearest_obstacle.get_pos();
|
||||
PT(BoundingVolume) bounds =_nearest_obstacle.get_bounds();
|
||||
CPT(BoundingSphere) bsphere = bounds->as_bounding_sphere();
|
||||
PT(BoundingVolume) np_bounds = _ai_char->get_node_path().get_bounds();
|
||||
CPT(BoundingSphere) np_sphere = np_bounds->as_bounding_sphere();
|
||||
double distance_needed = offset.length() - bsphere->get_radius() - np_sphere->get_radius();
|
||||
if((obstacle_detection())) {
|
||||
LVecBase3 direction = _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3::forward());
|
||||
direction.normalize();
|
||||
float forward_component = offset.dot(direction);
|
||||
LVecBase3 projection = forward_component * direction;
|
||||
LVecBase3 perpendicular_component = offset - projection;
|
||||
double p = perpendicular_component.length();
|
||||
perpendicular_component.normalize();
|
||||
LVecBase3 avoidance = perpendicular_component;
|
||||
// The more closer the obstacle, the more force it generates
|
||||
avoidance = (avoidance * _ai_char->get_max_force() * _ai_char->_movt_force) / (p + 0.01);
|
||||
return avoidance;
|
||||
}
|
||||
_ai_char->_steering->turn_on("obstacle_avoidance_activate");
|
||||
_ai_char->_steering->turn_off("obstacle_avoidance");
|
||||
return LVecBase3(0, 0, 0);
|
||||
}
|
39
build/nirai/panda3d/contrib/src/ai/obstacleAvoidance.h
Normal file
39
build/nirai/panda3d/contrib/src/ai/obstacleAvoidance.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef OBSTACLE_AVOIDANCE_H
|
||||
#define OBSTACLE_AVOIDANCE_H
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : obstacleAvoidance.h
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 10 Nov 2009
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "aiCharacter.h"
|
||||
#include "boundingSphere.h"
|
||||
|
||||
class AICharacter;
|
||||
|
||||
class EXPCL_PANDAAI ObstacleAvoidance {
|
||||
public :
|
||||
AICharacter *_ai_char;
|
||||
float _obstacle_avoidance_weight;
|
||||
NodePath _nearest_obstacle;
|
||||
bool _obstacle_avoidance_done;
|
||||
float _feeler;
|
||||
|
||||
ObstacleAvoidance(AICharacter *ai_char, float feeler_length);
|
||||
LVecBase3 do_obstacle_avoidance();
|
||||
~ObstacleAvoidance();
|
||||
void obstacle_avoidance_activate();
|
||||
bool obstacle_detection();
|
||||
};
|
||||
|
||||
#endif
|
1
build/nirai/panda3d/contrib/src/ai/p3ai_composite.cxx
Normal file
1
build/nirai/panda3d/contrib/src/ai/p3ai_composite.cxx
Normal file
|
@ -0,0 +1 @@
|
|||
#include "ai_composite1.cxx"
|
21
build/nirai/panda3d/contrib/src/ai/p3ai_composite1.cxx
Normal file
21
build/nirai/panda3d/contrib/src/ai/p3ai_composite1.cxx
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "config_ai.cxx"
|
||||
#include "aiWorld.cxx"
|
||||
#include "aiCharacter.cxx"
|
||||
#include "aiBehaviors.cxx"
|
||||
#include "seek.cxx"
|
||||
#include "flee.cxx"
|
||||
#include "pursue.cxx"
|
||||
#include "evade.cxx"
|
||||
#include "arrival.cxx"
|
||||
#include "flock.cxx"
|
||||
#include "wander.cxx"
|
||||
|
||||
#include "pathFollow.cxx"
|
||||
#include "obstacleAvoidance.cxx"
|
||||
|
||||
#include "pathFind.cxx"
|
||||
|
||||
#include "aiNode.cxx"
|
||||
|
||||
#include "aiPathFinder.cxx"
|
||||
#include "meshNode.cxx"
|
417
build/nirai/panda3d/contrib/src/ai/pathFind.cxx
Normal file
417
build/nirai/panda3d/contrib/src/ai/pathFind.cxx
Normal file
|
@ -0,0 +1,417 @@
|
|||
|
||||
#include "pathFind.h"
|
||||
|
||||
PathFind::PathFind(AICharacter *ai_ch) {
|
||||
_ai_char = ai_ch;
|
||||
|
||||
_parent = new GeomNode("parent");
|
||||
_ai_char->_window_render.attach_new_node(_parent);
|
||||
|
||||
_pen = new LineSegs("pen");
|
||||
_pen->set_color(1.0, 0.0, 0.0);
|
||||
_pen->set_thickness(2.0);
|
||||
|
||||
_path_finder_obj = NULL;
|
||||
_dynamic_avoid = false;
|
||||
}
|
||||
|
||||
PathFind::~PathFind() {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : create_nav_mesh
|
||||
// Description : This function recreates the navigation mesh from the .csv file
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFind::create_nav_mesh(const char* navmesh_filename) {
|
||||
// Stage variables.
|
||||
int grid_x, grid_y;
|
||||
float l, w, h;
|
||||
LVecBase3 position;
|
||||
|
||||
// Variable to hold line data read from file.
|
||||
string line;
|
||||
|
||||
// Array for storing data members obtained from each line of the file.
|
||||
string fields[10];
|
||||
|
||||
// Open data file for reading.
|
||||
ifstream nav_mesh_file (navmesh_filename);
|
||||
|
||||
if(nav_mesh_file.is_open()) {
|
||||
// Capture the grid size from the file.
|
||||
getline(nav_mesh_file, line);
|
||||
int pos = line.find(",");
|
||||
_grid_size = atoi((line.substr(pos + 1)).c_str());
|
||||
|
||||
// Initialize the stage mesh with NULL nodes.
|
||||
for(int r = 0; r < _grid_size; ++r) {
|
||||
_nav_mesh.push_back(vector<Node*>());
|
||||
for(int c = 0; c < _grid_size; ++c) {
|
||||
_nav_mesh[r].push_back(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore the header of the navmesh.csv file.
|
||||
getline(nav_mesh_file, line);
|
||||
|
||||
// Begin reading data from the file.
|
||||
while(!nav_mesh_file.eof()) {
|
||||
getline(nav_mesh_file, line);
|
||||
stringstream linestream (line);
|
||||
|
||||
// Stores all the data members in the line to the array.
|
||||
// Data structure: NULL,NodeType,GridX,GridY,Length,Width,Height,PosX,PosY,PosZ
|
||||
for(int i = 0; i < 10; ++i) {
|
||||
getline(linestream, fields[i], ',');
|
||||
}
|
||||
|
||||
// Populate the main nodes into stage mesh.
|
||||
if(fields[0] == "0" && fields[1] == "0") {
|
||||
grid_x = atoi(fields[2].c_str());
|
||||
grid_y = atoi(fields[3].c_str());
|
||||
l = atof(fields[4].c_str());
|
||||
w = atof(fields[5].c_str());
|
||||
h = atof(fields[6].c_str());
|
||||
position = LVecBase3(atof(fields[7].c_str()), atof(fields[8].c_str()), atof(fields[9].c_str()));
|
||||
|
||||
Node *stage_node = new Node(grid_x, grid_y, position, w, l, h);
|
||||
|
||||
|
||||
_nav_mesh[grid_y][grid_x] = stage_node;
|
||||
}
|
||||
else if(fields[0] == "") {
|
||||
// End of file reached at this point.
|
||||
nav_mesh_file.close();
|
||||
|
||||
// Assign the neighbor nodes for each of the main nodes that just got populated into the stage mesh.
|
||||
assign_neighbor_nodes(navmesh_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
cout<<"error opening navmesh.csv file!"<<endl;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : assign_neighbor_nodes
|
||||
// Description : This function assigns the neighbor nodes for each main node present in
|
||||
// _nav_mesh.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFind::assign_neighbor_nodes(const char* navmesh_filename){
|
||||
ifstream nav_mesh_file (navmesh_filename);
|
||||
|
||||
// Stage variables.
|
||||
int gd_x, gd_y, gd_xn, gd_yn;
|
||||
string ln;
|
||||
string fields[10];
|
||||
string fields_n[10];
|
||||
|
||||
if(nav_mesh_file.is_open()) {
|
||||
getline(nav_mesh_file, ln); // Get rid of grid size line.
|
||||
getline(nav_mesh_file, ln); // Get rid of the header.
|
||||
|
||||
while(!nav_mesh_file.eof()) {
|
||||
getline(nav_mesh_file, ln); // Gets main node data only. No neighbor nodes.
|
||||
stringstream linestream (ln);
|
||||
for(int i = 0; i < 10; ++i) {
|
||||
getline(linestream, fields[i], ',');
|
||||
}
|
||||
if(fields[0] == "0" && fields[1] == "0") {
|
||||
// Usable main node.
|
||||
gd_x = atoi(fields[2].c_str());
|
||||
gd_y = atoi(fields[3].c_str());
|
||||
for(int i = 0; i < 8; ++i) {
|
||||
getline(nav_mesh_file, ln); // Gets neighbor node data only. No main nodes.
|
||||
stringstream linestream_n (ln);
|
||||
for(int j = 0; j < 10; ++j) {
|
||||
getline(linestream_n, fields_n[j], ',');
|
||||
}
|
||||
gd_xn = atoi(fields_n[2].c_str());
|
||||
gd_yn = atoi(fields_n[3].c_str());
|
||||
|
||||
if(fields_n[0] == "0" && fields_n[1] == "1") {
|
||||
// Usable neighbor for main node.
|
||||
// TODO: The indices of the vector are inverted when compared to the values of the nodes on actual grid. Fix this!
|
||||
_nav_mesh[gd_y][gd_x]->_neighbours[i] = _nav_mesh[gd_yn][gd_xn];
|
||||
}
|
||||
else if(fields_n[0] == "1" && fields_n[1] == "1") {
|
||||
// NULL neighbor.
|
||||
_nav_mesh[gd_y][gd_x]->_neighbours[i] = NULL;
|
||||
}
|
||||
else {
|
||||
cout<<"Warning: Corrupt data!"<<endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(fields[0] == "") {
|
||||
// End of file reached at this point.
|
||||
nav_mesh_file.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
cout<<"error opening navmesh.csv file!"<<endl;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : set_path_find
|
||||
// Description : This function starts the path finding process after reading the given
|
||||
// navigation mesh.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void PathFind::set_path_find(const char* navmesh_filename) {
|
||||
create_nav_mesh(navmesh_filename);
|
||||
|
||||
if(_ai_char->_steering->_path_follow_obj) {
|
||||
_ai_char->_steering->remove_ai("pathfollow");
|
||||
}
|
||||
|
||||
_ai_char->_steering->path_follow(1.0f);
|
||||
|
||||
if(_path_finder_obj) {
|
||||
delete _path_finder_obj;
|
||||
_path_finder_obj = NULL;
|
||||
}
|
||||
|
||||
_path_finder_obj = new PathFinder(_nav_mesh);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : path_find (for pathfinding towards a static position)
|
||||
// Description : This function checks for the source and target in the navigation mesh
|
||||
// for its availability and then finds the best path via the A* algorithm
|
||||
// Then it calls the path follower to make the object follow the path.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void PathFind::path_find(LVecBase3 pos, string type) {
|
||||
if(type == "addPath") {
|
||||
if(_ai_char->_steering->_path_follow_obj) {
|
||||
_ai_char->_steering->remove_ai("pathfollow");
|
||||
}
|
||||
|
||||
_ai_char->_steering->path_follow(1.0f);
|
||||
}
|
||||
|
||||
clear_path();
|
||||
|
||||
Node* src = find_in_mesh(_nav_mesh, _ai_char->_ai_char_np.get_pos(_ai_char->_window_render), _grid_size);
|
||||
|
||||
if(src == NULL) {
|
||||
cout<<"couldnt find source"<<endl;
|
||||
}
|
||||
|
||||
Node* dst = find_in_mesh(_nav_mesh, pos, _grid_size);
|
||||
|
||||
if(dst == NULL) {
|
||||
cout<<"couldnt find destination"<<endl;
|
||||
}
|
||||
|
||||
if(src != NULL && dst != NULL) {
|
||||
_path_finder_obj->find_path(src, dst);
|
||||
trace_path(src);
|
||||
}
|
||||
|
||||
if(!_ai_char->_steering->_path_follow_obj->_start) {
|
||||
_ai_char->_steering->start_follow();
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : path_find (for pathfinding towards a moving target (a NodePath))
|
||||
// Description : This function checks for the source and target in the navigation mesh
|
||||
// for its availability and then finds the best path via the A* algorithm
|
||||
// Then it calls the path follower to make the object follow the path.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFind::path_find(NodePath target, string type) {
|
||||
if(type == "addPath") {
|
||||
if(_ai_char->_steering->_path_follow_obj) {
|
||||
_ai_char->_steering->remove_ai("pathfollow");
|
||||
}
|
||||
|
||||
_ai_char->_steering->path_follow(1.0f);
|
||||
}
|
||||
|
||||
clear_path();
|
||||
|
||||
_path_find_target = target;
|
||||
_prev_position = target.get_pos(_ai_char->_window_render);
|
||||
|
||||
Node* src = find_in_mesh(_nav_mesh, _ai_char->_ai_char_np.get_pos(_ai_char->_window_render), _grid_size);
|
||||
|
||||
if(src == NULL) {
|
||||
cout<<"couldnt find source"<<endl;
|
||||
}
|
||||
|
||||
Node* dst = find_in_mesh(_nav_mesh, _prev_position, _grid_size);
|
||||
|
||||
if(dst == NULL) {
|
||||
cout<<"couldnt find destination"<<endl;
|
||||
}
|
||||
|
||||
if(src != NULL && dst != NULL) {
|
||||
_path_finder_obj->find_path(src, dst);
|
||||
trace_path(src);
|
||||
}
|
||||
|
||||
if(_ai_char->_steering->_path_follow_obj!=NULL) {
|
||||
if(!_ai_char->_steering->_path_follow_obj->_start) {
|
||||
_ai_char->_steering->start_follow("pathfind");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : clear_path
|
||||
// Description : Helper function to restore the path and mesh to its initial state
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFind::clear_path() {
|
||||
// Initialize to zero
|
||||
for(int i = 0; i < _grid_size; ++i) {
|
||||
for(int j = 0; j < _grid_size; ++j) {
|
||||
if(_nav_mesh[i][j] != NULL) {
|
||||
_nav_mesh[i][j]->_status = _nav_mesh[i][j]->neutral;
|
||||
_nav_mesh[i][j]->_cost = 0;
|
||||
_nav_mesh[i][j]->_heuristic = 0;
|
||||
_nav_mesh[i][j]->_score = 0;
|
||||
_nav_mesh[i][j]->_prv_node = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(_path_finder_obj) {
|
||||
_path_finder_obj->_open_list.clear();
|
||||
_path_finder_obj->_closed_list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : trace_path
|
||||
// Description : This function is the function which sends the path information one by
|
||||
// one to the path follower so that it can store the path needed to be
|
||||
// traversed by the pathfinding object
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFind::trace_path(Node* src) {
|
||||
if(_ai_char->_pf_guide) {
|
||||
_parent->remove_all_children();
|
||||
}
|
||||
else {
|
||||
_parent->remove_all_children();
|
||||
}
|
||||
|
||||
if(_path_finder_obj->_closed_list.size() > 0) {
|
||||
Node *traversor = _path_finder_obj->_closed_list[_path_finder_obj->_closed_list.size() - 0.5];
|
||||
while(traversor != src) {
|
||||
if(_ai_char->_pf_guide) {
|
||||
_pen->move_to(traversor->_position.get_x(), traversor->_position.get_y(), 1);
|
||||
_pen->draw_to(traversor->_prv_node->_position.get_x(), traversor->_prv_node->_position.get_y(), 0.5);
|
||||
PT(GeomNode) gnode = _pen->create();
|
||||
_parent->add_child(gnode);
|
||||
}
|
||||
_ai_char->_steering->add_to_path(traversor->_position);
|
||||
traversor = traversor->_prv_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : add_obstacle_to_mesh
|
||||
// Description : This function allows the user to dynamically add obstacles to the
|
||||
// game environment. The function will update the nodes within the
|
||||
// bounding volume of the obstacle as non-traversable. Hence will not be
|
||||
// considered by the pathfinding algorithm.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFind::add_obstacle_to_mesh(NodePath obstacle) {
|
||||
PT(BoundingVolume) np_bounds = obstacle.get_bounds();
|
||||
CPT(BoundingSphere) np_sphere = np_bounds->as_bounding_sphere();
|
||||
|
||||
Node* temp = find_in_mesh(_nav_mesh, obstacle.get_pos(), _grid_size);
|
||||
|
||||
if(temp != NULL) {
|
||||
float left = temp->_position.get_x() - np_sphere->get_radius();
|
||||
float right = temp->_position.get_x() + np_sphere->get_radius();
|
||||
float top = temp->_position.get_y() + np_sphere->get_radius();
|
||||
float down = temp->_position.get_y() - np_sphere->get_radius();
|
||||
|
||||
for(int i = 0; i < _grid_size; ++i) {
|
||||
for(int j = 0; j < _grid_size; ++j) {
|
||||
if(_nav_mesh[i][j] != NULL && _nav_mesh[i][j]->_type == true) {
|
||||
if(_nav_mesh[i][j]->_position.get_x() >= left && _nav_mesh[i][j]->_position.get_x() <= right &&
|
||||
_nav_mesh[i][j]->_position.get_y() >= down && _nav_mesh[i][j]->_position.get_y() <= top) {
|
||||
_nav_mesh[i][j]->_type = false;
|
||||
_previous_obstacles.insert(_previous_obstacles.end(), i);
|
||||
_previous_obstacles.insert(_previous_obstacles.end(), j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : do_dynamic_avoid()
|
||||
// Description : This function does the updation of the collisions to the mesh based
|
||||
// on the new positions of the obstacles.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFind::do_dynamic_avoid() {
|
||||
clear_previous_obstacles();
|
||||
_previous_obstacles.clear();
|
||||
for(unsigned int i = 0; i < _dynamic_obstacle.size(); ++i) {
|
||||
add_obstacle_to_mesh(_dynamic_obstacle[i]);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : clear_previous_obstacles()
|
||||
// Description : Helper function to reset the collisions if the obstacle is not on the
|
||||
// node anymore
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFind::clear_previous_obstacles(){
|
||||
for(unsigned int i = 0; i < _previous_obstacles.size(); i = i + 2) {
|
||||
_nav_mesh[_previous_obstacles[i]][_previous_obstacles[i + 1]]->_type = true;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : dynamic_avoid
|
||||
// Description : This function starts the pathfinding obstacle navigation for the
|
||||
// passed in obstacle.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFind::dynamic_avoid(NodePath obstacle) {
|
||||
_dynamic_avoid = true;
|
||||
_dynamic_obstacle.insert(_dynamic_obstacle.end(), obstacle);
|
||||
}
|
72
build/nirai/panda3d/contrib/src/ai/pathFind.h
Normal file
72
build/nirai/panda3d/contrib/src/ai/pathFind.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : pathFind.h
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 12 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 _PATHFIND_H
|
||||
#define _PATHFIND_H
|
||||
|
||||
#include "aiGlobals.h"
|
||||
#include "aiCharacter.h"
|
||||
#include "aiPathFinder.h"
|
||||
#include "boundingSphere.h"
|
||||
|
||||
class AICharacter;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Class : PathFind
|
||||
// Description : This class contains all the members and functions that are required to form an interface between
|
||||
// the AIBehaviors class and the PathFinder class. An object (pointer) of this class is provided in the
|
||||
// AIBehaviors class. It is only via this object that the user can activate pathfinding.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class EXPCL_PANDAAI PathFind {
|
||||
public:
|
||||
AICharacter *_ai_char;
|
||||
PathFinder *_path_finder_obj;
|
||||
|
||||
NavMesh _nav_mesh;
|
||||
NavMesh _stage_mesh;
|
||||
|
||||
int _grid_size;
|
||||
NodePath _path_find_target;
|
||||
LVecBase3 _prev_position;
|
||||
PT(GeomNode) _parent;
|
||||
LineSegs *_pen;
|
||||
vector<int> _previous_obstacles;
|
||||
bool _dynamic_avoid;
|
||||
vector<NodePath> _dynamic_obstacle;
|
||||
|
||||
PathFind(AICharacter *ai_ch);
|
||||
~PathFind();
|
||||
|
||||
void clear_path();
|
||||
void trace_path(Node* src);
|
||||
|
||||
void create_nav_mesh(const char* navmesh_filename);
|
||||
void assign_neighbor_nodes(const char* navmesh_filename);
|
||||
void do_dynamic_avoid();
|
||||
void clear_previous_obstacles();
|
||||
|
||||
void set_path_find(const char* navmesh_filename);
|
||||
void path_find(LVecBase3 pos, string type = "normal");
|
||||
void path_find(NodePath target, string type = "normal");
|
||||
void add_obstacle_to_mesh(NodePath obstacle);
|
||||
void dynamic_avoid(NodePath obstacle);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
131
build/nirai/panda3d/contrib/src/ai/pathFollow.cxx
Normal file
131
build/nirai/panda3d/contrib/src/ai/pathFollow.cxx
Normal file
|
@ -0,0 +1,131 @@
|
|||
|
||||
#include "pathFollow.h"
|
||||
|
||||
PathFollow::PathFollow(AICharacter *ai_ch, float follow_wt) {
|
||||
_follow_weight = follow_wt;
|
||||
_curr_path_waypoint = -1;
|
||||
_start = false;
|
||||
_ai_char = ai_ch;
|
||||
_myClock = ClockObject::get_global_clock();
|
||||
}
|
||||
|
||||
PathFollow::~PathFollow() {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : add_to_path
|
||||
// Description : This function adds the positions generated from a pathfind or a simple
|
||||
// path follow behavior to the _path list.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFollow::add_to_path(LVecBase3 pos) {
|
||||
_path.push_back(pos);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : start
|
||||
// Description : This function initiates the path follow behavior.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFollow::start(string type) {
|
||||
_type = type;
|
||||
_start = true;
|
||||
if(_path.size() > 0) {
|
||||
_curr_path_waypoint = _path.size() - 1;
|
||||
_dummy = _ai_char->_window_render.attach_new_node("dummy");
|
||||
_dummy.set_pos(_path[_curr_path_waypoint]);
|
||||
_ai_char->_steering->pursue(_dummy, _follow_weight);
|
||||
_time = _myClock->get_real_time();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : do_follow
|
||||
// Description : This function allows continuous path finding by ai chars. There are 2
|
||||
// ways in which this is implemented.
|
||||
// 1. The character re-calculates the optimal path everytime the target
|
||||
// changes its position. Less computationally expensive.
|
||||
// 2. The character continuosly re-calculates its optimal path to the
|
||||
// target. This is used in a scenario where the ai chars have to avoid
|
||||
// other ai chars. More computationally expensive.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PathFollow::do_follow() {
|
||||
if((_myClock->get_real_time() - _time) > 0.5) {
|
||||
if(_type=="pathfind") {
|
||||
// This 'if' statement when 'true' causes the path to be re-calculated irrespective of target position.
|
||||
// This is done when _dynamice_avoid is active. More computationally expensive.
|
||||
if(_ai_char->_steering->_path_find_obj->_dynamic_avoid) {
|
||||
_ai_char->_steering->_path_find_obj->do_dynamic_avoid();
|
||||
if(check_if_possible()) {
|
||||
_path.clear();
|
||||
_ai_char->_steering->_path_find_obj->path_find(_ai_char->_steering->_path_find_obj->_path_find_target);
|
||||
// Ensure that the path size is not 0.
|
||||
if(_path.size() > 0) {
|
||||
_curr_path_waypoint = _path.size() - 1;
|
||||
_dummy.set_pos(_path[_curr_path_waypoint]);
|
||||
}
|
||||
else {
|
||||
// Refresh the _curr_path_waypoint value if path size is <= 0.
|
||||
_curr_path_waypoint = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// This 'if' statement causes the path to be re-calculated only when there is a change in target position.
|
||||
// Less computationally expensive.
|
||||
else if(_ai_char->_steering->_path_find_obj->_path_find_target.get_pos(_ai_char->_window_render)
|
||||
!= _ai_char->_steering->_path_find_obj->_prev_position) {
|
||||
if(check_if_possible()) {
|
||||
_path.clear();
|
||||
_ai_char->_steering->_path_find_obj->path_find(_ai_char->_steering->_path_find_obj->_path_find_target);
|
||||
// Ensure that the path size is not 0.
|
||||
if(_path.size() > 0) {
|
||||
_curr_path_waypoint = _path.size() - 1;
|
||||
_dummy.set_pos(_path[_curr_path_waypoint]);
|
||||
}
|
||||
else {
|
||||
// Refresh the _curr_path_waypoint value if path size is 0.
|
||||
_curr_path_waypoint = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
_time = _myClock->get_real_time();
|
||||
}
|
||||
}
|
||||
|
||||
if(_curr_path_waypoint > 0) {
|
||||
double distance = (_path[_curr_path_waypoint] - _ai_char->_ai_char_np.get_pos(_ai_char->_window_render)).length();
|
||||
|
||||
if(distance < 5) {
|
||||
_curr_path_waypoint--;
|
||||
_dummy.set_pos(_path[_curr_path_waypoint]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : check_if_possible
|
||||
// Description : This function checks if the current positions of the ai char and the
|
||||
// target char can be used to generate an optimal path.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool PathFollow::check_if_possible() {
|
||||
Node* src = find_in_mesh(_ai_char->_steering->_path_find_obj->_nav_mesh, _ai_char->_ai_char_np.get_pos(_ai_char->_window_render), _ai_char->_steering->_path_find_obj->_grid_size);
|
||||
LVecBase3 _prev_position = _ai_char->_steering->_path_find_obj->_path_find_target.get_pos(_ai_char->_window_render);
|
||||
Node* dst = find_in_mesh(_ai_char->_steering->_path_find_obj->_nav_mesh, _prev_position, _ai_char->_steering->_path_find_obj->_grid_size);
|
||||
|
||||
if(src && dst) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
32
build/nirai/panda3d/contrib/src/ai/pathFollow.h
Normal file
32
build/nirai/panda3d/contrib/src/ai/pathFollow.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
|
||||
#ifndef _PATHFOLLOW_H
|
||||
#define _PATHFOLLOW_H
|
||||
|
||||
#include "aiGlobals.h"
|
||||
#include "aiCharacter.h"
|
||||
#include "meshNode.h"
|
||||
|
||||
class AICharacter;
|
||||
|
||||
class EXPCL_PANDAAI PathFollow {
|
||||
|
||||
public:
|
||||
AICharacter *_ai_char;
|
||||
float _follow_weight;
|
||||
vector<LVecBase3> _path;
|
||||
int _curr_path_waypoint;
|
||||
bool _start;
|
||||
NodePath _dummy;
|
||||
string _type;
|
||||
ClockObject *_myClock;
|
||||
float _time;
|
||||
|
||||
PathFollow(AICharacter *ai_ch, float follow_wt);
|
||||
~PathFollow();
|
||||
void add_to_path(LVecBase3 pos);
|
||||
void start(string type);
|
||||
void do_follow();
|
||||
bool check_if_possible();
|
||||
};
|
||||
|
||||
#endif
|
61
build/nirai/panda3d/contrib/src/ai/pursue.cxx
Normal file
61
build/nirai/panda3d/contrib/src/ai/pursue.cxx
Normal file
|
@ -0,0 +1,61 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : pursue.cxx
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 24 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "pursue.h"
|
||||
|
||||
Pursue::Pursue(AICharacter *ai_ch, NodePath target_object, float pursue_wt) {
|
||||
_ai_char = ai_ch;
|
||||
|
||||
_pursue_target = target_object;
|
||||
_pursue_weight = pursue_wt;
|
||||
|
||||
_pursue_done = false;
|
||||
}
|
||||
|
||||
Pursue::~Pursue() {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : do_pursue
|
||||
// Description : This function performs the pursue and returns a pursue force which is used
|
||||
// in the calculate_prioritized function.
|
||||
// In case the target has been reached it resets the forces to 0 so that the character stops.
|
||||
// This function is not to be used by the user.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LVecBase3 Pursue::do_pursue() {
|
||||
assert(_pursue_target && "pursue target not assigned");
|
||||
|
||||
LVecBase3 present_pos = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
|
||||
double target_distance = (_pursue_target.get_pos(_ai_char->_window_render) - present_pos).length();
|
||||
|
||||
if(int(target_distance) == 0) {
|
||||
_pursue_done = true;
|
||||
_ai_char->_steering->_steering_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
_ai_char->_steering->_pursue_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
return(LVecBase3(0.0, 0.0, 0.0));
|
||||
}
|
||||
else {
|
||||
_pursue_done = false;
|
||||
}
|
||||
|
||||
_pursue_direction = _pursue_target.get_pos(_ai_char->_window_render) - present_pos;
|
||||
_pursue_direction.normalize();
|
||||
|
||||
LVecBase3 desired_force = _pursue_direction * _ai_char->_movt_force;
|
||||
return(desired_force);
|
||||
}
|
39
build/nirai/panda3d/contrib/src/ai/pursue.h
Normal file
39
build/nirai/panda3d/contrib/src/ai/pursue.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : pursue.h
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 24 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 _PURSUE_H
|
||||
#define _PURSUE_H
|
||||
|
||||
#include "aiGlobals.h"
|
||||
#include "aiCharacter.h"
|
||||
|
||||
class AICharacter;
|
||||
|
||||
class EXPCL_PANDAAI Pursue {
|
||||
|
||||
public:
|
||||
AICharacter *_ai_char;
|
||||
|
||||
NodePath _pursue_target;
|
||||
float _pursue_weight;
|
||||
LVecBase3 _pursue_direction;
|
||||
bool _pursue_done;
|
||||
|
||||
Pursue(AICharacter *ai_ch, NodePath target_object, float pursue_wt);
|
||||
~Pursue();
|
||||
LVecBase3 do_pursue();
|
||||
};
|
||||
|
||||
#endif
|
66
build/nirai/panda3d/contrib/src/ai/seek.cxx
Normal file
66
build/nirai/panda3d/contrib/src/ai/seek.cxx
Normal file
|
@ -0,0 +1,66 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : seek.cxx
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 24 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "seek.h"
|
||||
|
||||
Seek::Seek(AICharacter *ai_ch, NodePath target_object, float seek_wt) {
|
||||
_ai_char = ai_ch;
|
||||
|
||||
_seek_position = target_object.get_pos(_ai_char->_window_render);
|
||||
_seek_weight = seek_wt;
|
||||
|
||||
_seek_direction = _seek_position - _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
|
||||
_seek_direction.normalize();
|
||||
|
||||
_seek_done = false;
|
||||
}
|
||||
|
||||
Seek::Seek(AICharacter *ai_ch, LVecBase3 pos, float seek_wt) {
|
||||
_ai_char = ai_ch;
|
||||
|
||||
_seek_position = pos;
|
||||
_seek_weight = seek_wt;
|
||||
|
||||
_seek_direction = _seek_position - _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
|
||||
_seek_direction.normalize();
|
||||
|
||||
_seek_done = false;
|
||||
}
|
||||
|
||||
Seek::~Seek() {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : do_seek
|
||||
// Description : This function performs the seek and returns a seek force which is used
|
||||
// in the calculate_prioritized function.
|
||||
// This function is not to be used by the user.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LVecBase3 Seek::do_seek() {
|
||||
double target_distance = (_seek_position - _ai_char->_ai_char_np.get_pos(_ai_char->_window_render)).length();
|
||||
|
||||
if(int(target_distance) == 0) {
|
||||
_seek_done = true;
|
||||
_ai_char->_steering->_steering_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
_ai_char->_steering->turn_off("seek");
|
||||
return(LVecBase3(0.0, 0.0, 0.0));
|
||||
}
|
||||
|
||||
LVecBase3 desired_force = _seek_direction * _ai_char->_movt_force;
|
||||
return(desired_force);
|
||||
}
|
41
build/nirai/panda3d/contrib/src/ai/seek.h
Normal file
41
build/nirai/panda3d/contrib/src/ai/seek.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : seek.h
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 24 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 _SEEK_H
|
||||
#define _SEEK_H
|
||||
|
||||
#include "aiGlobals.h"
|
||||
#include "aiCharacter.h"
|
||||
|
||||
class AICharacter;
|
||||
|
||||
class EXPCL_PANDAAI Seek {
|
||||
|
||||
public:
|
||||
AICharacter *_ai_char;
|
||||
|
||||
LVecBase3 _seek_position;
|
||||
float _seek_weight;
|
||||
LVecBase3 _seek_direction;
|
||||
bool _seek_done;
|
||||
LVecBase3 _seek_accum_force;
|
||||
|
||||
Seek(AICharacter *ai_ch, NodePath target_object, float seek_wt = 1.0);
|
||||
Seek(AICharacter *ai_ch, LVecBase3 pos, float seek_wt = 1.0);
|
||||
~Seek();
|
||||
LVecBase3 do_seek();
|
||||
};
|
||||
|
||||
#endif
|
142
build/nirai/panda3d/contrib/src/ai/wander.cxx
Normal file
142
build/nirai/panda3d/contrib/src/ai/wander.cxx
Normal file
|
@ -0,0 +1,142 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : wander.cxx
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 24 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "wander.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : rand_float
|
||||
// Description : This function creates a random float point number
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double rand_float() {
|
||||
const static double rand_max = 0x7fff;
|
||||
return ((rand()) / (rand_max + 1.0));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : random_clamped
|
||||
// Description : This function returns a random floating point number in the range
|
||||
// -1 to 1.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
double random_clamped() {
|
||||
return (rand_float() - rand_float());
|
||||
}
|
||||
|
||||
Wander::Wander(AICharacter *ai_ch, double wander_radius,int flag, double aoe, float wander_weight) {
|
||||
_ai_char = ai_ch;
|
||||
_wander_radius = wander_radius ;
|
||||
_wander_weight = wander_weight;
|
||||
double theta = rand_float() * 2 * 3.14159;
|
||||
double si = rand_float() * 3.14159;
|
||||
_flag = flag;
|
||||
// Area around which the character should wander
|
||||
_area_of_effect = aoe;
|
||||
_init_pos = _ai_char->get_node_path().get_pos(_ai_char->get_char_render());
|
||||
// _flag is used by Wander to wander in a given axis
|
||||
// Value 0 - XY axes wander
|
||||
// Value 1 - YZ axes wander
|
||||
// Value 2 - XZ axes wander
|
||||
// Value 3 - XYZ axes wander
|
||||
// default is XY axes
|
||||
switch(_flag) {
|
||||
case 0: {
|
||||
_wander_target = LVecBase3(_wander_radius * cos(theta), _wander_radius * sin(theta),0);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
_wander_target = LVecBase3(0, _wander_radius * cos(theta), _wander_radius * sin(theta));
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
_wander_target = LVecBase3(_wander_radius * cos(theta), 0, _wander_radius * sin(theta));
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
_wander_target = LVecBase3(_wander_radius * sin(theta) * cos(si), _wander_radius * sin(theta) * sin(si), _wander_radius * cos(theta));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
_wander_target = LVecBase3(_wander_radius * cos(theta), _wander_radius * sin(theta),0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Wander::~Wander() {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function : do_wander
|
||||
// Description : This function performs the wander and returns the wander force which is used
|
||||
// in the calculate_prioritized function.
|
||||
// This function is not to be used by the user.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LVecBase3 Wander::do_wander() {
|
||||
LVecBase3 present_pos = _ai_char->get_node_path().get_pos(_ai_char->get_char_render());
|
||||
// Create the random slices to enable random movement of wander for x,y,z respectively
|
||||
double time_slice_1 = random_clamped() * 1.5;
|
||||
double time_slice_2 = random_clamped() * 1.5;
|
||||
double time_slice_3 = random_clamped() * 1.5;
|
||||
switch(_flag) {
|
||||
case 0: {
|
||||
_wander_target += LVecBase3(time_slice_1, time_slice_2, 0);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
_wander_target += LVecBase3(0, time_slice_1, time_slice_2);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
_wander_target += LVecBase3(time_slice_1, 0, time_slice_2);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
_wander_target += LVecBase3(time_slice_1, time_slice_2, time_slice_3);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
_wander_target = LVecBase3(time_slice_1, time_slice_2, 0);
|
||||
}
|
||||
}
|
||||
_wander_target.normalize();
|
||||
_wander_target *= _wander_radius;
|
||||
LVecBase3 target = _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3::forward());
|
||||
target.normalize();
|
||||
// Project wander target onto global space
|
||||
target = _wander_target + target;
|
||||
LVecBase3 desired_target = present_pos + target;
|
||||
LVecBase3 desired_force = desired_target - _ai_char->get_node_path().get_pos() ;
|
||||
desired_force.normalize();
|
||||
desired_force *= _ai_char->_movt_force;
|
||||
double distance = (present_pos - _init_pos).length();
|
||||
if(_area_of_effect > 0 && distance > _area_of_effect) {
|
||||
LVecBase3 direction = present_pos - _init_pos;
|
||||
direction.normalize();
|
||||
desired_force = - direction * _ai_char->_movt_force;
|
||||
LVecBase3 dirn = _ai_char->_steering->_steering_force;
|
||||
dirn.normalize();
|
||||
_ai_char->_steering->_steering_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
}
|
||||
return desired_force;
|
||||
}
|
38
build/nirai/panda3d/contrib/src/ai/wander.h
Normal file
38
build/nirai/panda3d/contrib/src/ai/wander.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
// Filename : wander.h
|
||||
// Created by : Deepak, John, Navin
|
||||
// Date : 24 Oct 09
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 _WANDER_H
|
||||
#define _WANDER_H
|
||||
|
||||
#include "aiCharacter.h"
|
||||
|
||||
class AICharacter;
|
||||
|
||||
class EXPCL_PANDAAI Wander {
|
||||
public:
|
||||
AICharacter *_ai_char;
|
||||
double _wander_radius;
|
||||
LVecBase3 _wander_target;
|
||||
float _wander_weight;
|
||||
int _flag;
|
||||
LVecBase3 _init_pos;
|
||||
double _area_of_effect;
|
||||
|
||||
Wander(AICharacter *ai_ch, double wander_radius, int flag, double aoe, float wander_weight);
|
||||
LVecBase3 do_wander();
|
||||
~Wander();
|
||||
};
|
||||
|
||||
#endif
|
13
build/nirai/panda3d/contrib/src/contribbase/Sources.pp
Normal file
13
build/nirai/panda3d/contrib/src/contribbase/Sources.pp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#define OTHER_LIBS p3interrogatedb:c p3dconfig:c p3dtoolconfig:m \
|
||||
p3dtoolutil:c p3dtoolbase:c p3dtool:m p3prc:c
|
||||
|
||||
#begin lib_target
|
||||
#define TARGET p3contribbase
|
||||
|
||||
#define SOURCES \
|
||||
contribbase.cxx contribbase.h contribsymbols.h \
|
||||
|
||||
#define INSTALL_HEADERS \
|
||||
contribbase.h contribbase.h
|
||||
|
||||
#end lib_target
|
15
build/nirai/panda3d/contrib/src/contribbase/contribbase.cxx
Normal file
15
build/nirai/panda3d/contrib/src/contribbase/contribbase.cxx
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Filename: contribbase.cxx
|
||||
// Created by: rdb (26Apr10)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "contribbase.h"
|
26
build/nirai/panda3d/contrib/src/contribbase/contribbase.h
Normal file
26
build/nirai/panda3d/contrib/src/contribbase/contribbase.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* Filename: contribbase.h
|
||||
* Created by: rdb (30Dec09)
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 is included at the beginning of every header file and/or
|
||||
C or C++ file. It must be compilable for C as well as C++ files,
|
||||
so no C++-specific code or syntax can be put here. */
|
||||
|
||||
#ifndef CONTRIBBASE_H
|
||||
#define CONTRIBBASE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "contribsymbols.h"
|
||||
|
||||
#endif
|
||||
|
33
build/nirai/panda3d/contrib/src/contribbase/contribsymbols.h
Normal file
33
build/nirai/panda3d/contrib/src/contribbase/contribsymbols.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* Filename: contribsymbols.h
|
||||
* Created by: rdb (30Dec09)
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 CONTRIBSYMBOLS_H
|
||||
#define CONTRIBSYMBOLS_H
|
||||
|
||||
/* See dtoolsymbols.h for a rant on the purpose of this file. */
|
||||
|
||||
/* Note that the symbols declared in this file appear in alphabetical
|
||||
order. Also note that we must use C-style comments only here, not
|
||||
C++-style comments, since this file is occasionally included by a C
|
||||
file. */
|
||||
|
||||
#ifdef BUILDING_PANDAAI
|
||||
#define EXPCL_PANDAAI EXPORT_CLASS
|
||||
#define EXPTP_PANDAAI EXPORT_TEMPL
|
||||
#else
|
||||
#define EXPCL_PANDAAI IMPORT_CLASS
|
||||
#define EXPTP_PANDAAI IMPORT_TEMPL
|
||||
#endif
|
||||
|
||||
#endif
|
2
build/nirai/panda3d/contrib/src/panda3dtoolsgui/.gitignore
vendored
Normal file
2
build/nirai/panda3d/contrib/src/panda3dtoolsgui/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/build
|
||||
/dist
|
3190
build/nirai/panda3d/contrib/src/panda3dtoolsgui/Panda3DToolsGUI.py
Normal file
3190
build/nirai/panda3d/contrib/src/panda3dtoolsgui/Panda3DToolsGUI.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,3 @@
|
|||
python setup.py py2exe
|
||||
|
||||
explorer .\dist
|
BIN
build/nirai/panda3d/contrib/src/panda3dtoolsgui/pandaIcon.ico
Normal file
BIN
build/nirai/panda3d/contrib/src/panda3dtoolsgui/pandaIcon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 281 KiB |
4
build/nirai/panda3d/contrib/src/panda3dtoolsgui/setup.py
Normal file
4
build/nirai/panda3d/contrib/src/panda3dtoolsgui/setup.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from distutils.core import setup
|
||||
import py2exe
|
||||
|
||||
setup(console=['Panda3DToolsGUI.py'])
|
188
build/nirai/panda3d/contrib/src/sceneeditor/AlignTool.py
Normal file
188
build/nirai/panda3d/contrib/src/sceneeditor/AlignTool.py
Normal file
|
@ -0,0 +1,188 @@
|
|||
#################################################################
|
||||
# AlignTool.py
|
||||
# Written by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#################################################################
|
||||
from direct.tkwidgets.AppShell import *
|
||||
from direct.showbase.TkGlobal import *
|
||||
|
||||
|
||||
class AlignTool(AppShell):
|
||||
#################################################################
|
||||
# AlignTool(AppShell)
|
||||
#################################################################
|
||||
appversion = '1.0'
|
||||
appname = 'Align Tool'
|
||||
frameWidth = 220
|
||||
frameHeight = 330
|
||||
frameIniPosX = 250
|
||||
frameIniPosY = 250
|
||||
padx = 0
|
||||
pady = 0
|
||||
|
||||
|
||||
def __init__(self, list = [], parent = None, nodePath = None, **kw):
|
||||
# Keep nodePath Data
|
||||
self.nodePath = nodePath
|
||||
self.targetList = list
|
||||
self.targetName = None
|
||||
# Rename App
|
||||
self.appname += (' '+self.nodePath.getName())
|
||||
# Define the megawidget options.
|
||||
optiondefs = (
|
||||
('title', self.appname, None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
if parent == None:
|
||||
self.parent = Toplevel()
|
||||
AppShell.__init__(self, self.parent)
|
||||
self.parent.geometry('%dx%d+%d+%d' % (self.frameWidth, self.frameHeight,self.frameIniPosX,self.frameIniPosY))
|
||||
|
||||
self.initialiseoptions(AlignTool)
|
||||
|
||||
self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
|
||||
|
||||
def appInit(self):
|
||||
return
|
||||
|
||||
def createInterface(self):
|
||||
# The interior of the toplevel panel
|
||||
interior = self.interior()
|
||||
mainFrame = Frame(interior)
|
||||
frame = Frame(mainFrame)
|
||||
self.nameBox = self.createcomponent(
|
||||
'Align Target', (), None,
|
||||
Pmw.ComboBox, (frame,),
|
||||
labelpos = W, label_text='Target Node:', entry_width = 20, entry_state = DISABLED,
|
||||
selectioncommand = self.setTargetNode,
|
||||
scrolledlist_items = self.targetList)
|
||||
self.nameBox.pack(side=LEFT)
|
||||
frame.pack(side=TOP, fill = X, expand = 1,pady=5)
|
||||
group = Pmw.Group(mainFrame, tag_text = 'Setting')
|
||||
group.pack(side=TOP, fill = 'both', expand = 1,pady=5)
|
||||
groupFrame = group.interior()
|
||||
# X and H checkbox
|
||||
frame = Frame(groupFrame)
|
||||
self.alignXVar = IntVar()
|
||||
self.alignXVar.set(False)
|
||||
self.alignXButton = Checkbutton(
|
||||
frame,
|
||||
text = ': Align X',
|
||||
variable = self.alignXVar)
|
||||
self.alignXButton.pack(side=LEFT, expand=False)
|
||||
self.alignHVar = IntVar()
|
||||
self.alignHVar.set(False)
|
||||
self.alignHButton = Checkbutton(
|
||||
frame,
|
||||
text = ': Align H',
|
||||
variable = self.alignHVar)
|
||||
self.alignHButton.pack(side=RIGHT, expand=False)
|
||||
frame.pack(side=TOP, fill = X, expand = 1,pady=5)
|
||||
|
||||
groupFrame.pack(side=TOP, fill = 'both', expand = 1,padx=5,pady=5)
|
||||
|
||||
frame = Frame(mainFrame)
|
||||
Button(frame, text='Align', width = 13, command=self.Align_press).pack(side=LEFT)
|
||||
Button(frame, text='OK', width = 13, command=self.ok_press).pack(side=RIGHT)
|
||||
frame.pack(side=BOTTOM, fill = X, expand = 1,pady=5)
|
||||
|
||||
# Y and P checkbox
|
||||
frame = Frame(groupFrame)
|
||||
self.alignYVar = IntVar()
|
||||
self.alignYVar.set(False)
|
||||
self.alignYButton = Checkbutton(
|
||||
frame,
|
||||
text = ': Align Y',
|
||||
variable = self.alignYVar)
|
||||
self.alignYButton.pack(side=LEFT, expand=False)
|
||||
self.alignPVar = IntVar()
|
||||
self.alignPVar.set(False)
|
||||
self.alignPButton = Checkbutton(
|
||||
frame,
|
||||
text = ': Align P',
|
||||
variable = self.alignPVar)
|
||||
self.alignPButton.pack(side=RIGHT, expand=False)
|
||||
frame.pack(side=TOP, fill = X, expand = 1,pady=5)
|
||||
|
||||
# Z and R checkbox
|
||||
frame = Frame(groupFrame)
|
||||
self.alignZVar = IntVar()
|
||||
self.alignZVar.set(False)
|
||||
self.alignZButton = Checkbutton(
|
||||
frame,
|
||||
text = ': Align Z',
|
||||
variable = self.alignZVar)
|
||||
self.alignZButton.pack(side=LEFT, expand=False)
|
||||
self.alignRVar = IntVar()
|
||||
self.alignRVar.set(False)
|
||||
self.alignRButton = Checkbutton(
|
||||
frame,
|
||||
text = ': Align R',
|
||||
variable = self.alignRVar)
|
||||
self.alignRButton.pack(side=RIGHT, expand=False)
|
||||
frame.pack(side=TOP, fill = X, expand = 1,pady=5)
|
||||
|
||||
# Scale
|
||||
frame = Frame(groupFrame)
|
||||
Label(frame,text='Align Scale:').pack(side=LEFT)
|
||||
frame.pack(side=TOP, fill = X, expand = 1,pady=5)
|
||||
frame = Frame(groupFrame)
|
||||
self.alignSXVar = IntVar()
|
||||
self.alignSXVar.set(False)
|
||||
self.alignSXButton = Checkbutton(
|
||||
frame,
|
||||
text = ': X',
|
||||
variable = self.alignSXVar)
|
||||
self.alignSXButton.pack(side=LEFT, expand=False)
|
||||
self.alignSYVar = IntVar()
|
||||
self.alignSYVar.set(False)
|
||||
self.alignSYButton = Checkbutton(
|
||||
frame,
|
||||
text = ': Y',
|
||||
variable = self.alignSYVar)
|
||||
self.alignSYButton.pack(side=LEFT, expand=False)
|
||||
frame.pack(side=TOP, fill = X, expand = 1,pady=5)
|
||||
self.alignSZVar = IntVar()
|
||||
self.alignSZVar.set(False)
|
||||
self.alignSZButton = Checkbutton(
|
||||
frame,
|
||||
text = ': Z',
|
||||
variable = self.alignSZVar)
|
||||
self.alignSZButton.pack(side=LEFT, expand=False)
|
||||
frame.pack(side=TOP, fill = X, expand = 1,pady=5)
|
||||
|
||||
|
||||
mainFrame.pack(fill = 'both', expand = 1,padx=7,pady=7)
|
||||
|
||||
|
||||
def createMenuBar(self):
|
||||
self.menuBar.destroy()
|
||||
|
||||
def onDestroy(self, event):
|
||||
messenger.send('ALW_close', [self.nodePath.getName()])
|
||||
'''
|
||||
If you have open any thing, please rewrite here!
|
||||
'''
|
||||
pass
|
||||
|
||||
###############################
|
||||
|
||||
def ok_press(self):
|
||||
#################################################################
|
||||
# ok_press(self)
|
||||
# Callback function
|
||||
# This function will be called when user click on the "OK" button on the window.
|
||||
#################################################################
|
||||
self.quit()
|
||||
|
||||
def Align_press(self):
|
||||
list = [self.alignXVar.get(), self.alignYVar.get(), self.alignZVar.get(),
|
||||
self.alignHVar.get(), self.alignPVar.get(), self.alignRVar.get(),
|
||||
self.alignSXVar.get(), self.alignSYVar.get(), self.alignSZVar.get()]
|
||||
if self.targetName != None:
|
||||
messenger.send('ALW_align', [self.nodePath, self.targetName, list])
|
||||
return
|
||||
|
||||
def setTargetNode(self,name=None):
|
||||
self.targetName = name
|
||||
return
|
||||
|
59
build/nirai/panda3d/contrib/src/sceneeditor/MetadataPanel.py
Normal file
59
build/nirai/panda3d/contrib/src/sceneeditor/MetadataPanel.py
Normal file
|
@ -0,0 +1,59 @@
|
|||
from direct.tkwidgets.AppShell import *
|
||||
from direct.showbase.TkGlobal import *
|
||||
import Pmw
|
||||
|
||||
class MetadataPanel(AppShell,Pmw.MegaWidget):
|
||||
appversion = '1.0'
|
||||
appname = 'Metadata Panel'
|
||||
frameWidth = 400
|
||||
frameHeight = 400
|
||||
padx = 0
|
||||
pady = 0
|
||||
usecommandarea = 0
|
||||
usestatusarea = 0
|
||||
Metatag=""
|
||||
Metanode=None
|
||||
tag_text=None
|
||||
def __init__(self,nodePath,parent=None,**kw):
|
||||
|
||||
# Initialise superclass
|
||||
Pmw.MegaWidget.__init__(self, parent)
|
||||
|
||||
# Define the megawidget options.
|
||||
optiondefs = (
|
||||
('title', self.appname, None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
self.Metanode=nodePath
|
||||
if(nodePath.hasTag("Metadata")):
|
||||
self.Metatag=self.Metanode.getTag("Metadata")
|
||||
|
||||
if parent == None:
|
||||
self.parent = Toplevel()
|
||||
AppShell.__init__(self, self.parent)
|
||||
|
||||
self.parent.resizable(False,False)
|
||||
|
||||
|
||||
def appInit(self):
|
||||
print "Metadata Panel"
|
||||
|
||||
def createInterface(self):
|
||||
interior = self.interior()
|
||||
mainFrame = Frame(interior)
|
||||
tag_label=Label (mainFrame,text="Enter Metadata",font=('MSSansSerif', 15),
|
||||
relief = RIDGE, borderwidth=5)
|
||||
tag_label.pack()
|
||||
source=StringVar()
|
||||
source.set(self.Metatag)
|
||||
self.tag_text=Entry(mainFrame, width=10,textvariable=source)
|
||||
self.tag_text.pack()
|
||||
set_button=Button(mainFrame, text='Set Metadata',font=('MSSansSerif', 15),
|
||||
relief = RIDGE, borderwidth=5, command= lambda:self.SetIt())
|
||||
set_button.pack()
|
||||
mainFrame.pack(fill = 'both', expand = 1)
|
||||
|
||||
def SetIt(self):
|
||||
self.Metanode.setTag("Metadata",self.tag_text.get())
|
||||
|
||||
|
458
build/nirai/panda3d/contrib/src/sceneeditor/SideWindow.py
Normal file
458
build/nirai/panda3d/contrib/src/sceneeditor/SideWindow.py
Normal file
|
@ -0,0 +1,458 @@
|
|||
#################################################################
|
||||
# sideWindow.py
|
||||
# Written by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#################################################################
|
||||
from direct.tkwidgets.AppShell import AppShell
|
||||
from direct.tkwidgets.VectorWidgets import ColorEntry
|
||||
from direct.showbase.TkGlobal import spawnTkLoop
|
||||
import seSceneGraphExplorer
|
||||
from Tkinter import Frame, IntVar, Checkbutton, Toplevel
|
||||
import Pmw, Tkinter
|
||||
|
||||
class sideWindow(AppShell):
|
||||
#################################################################
|
||||
# sideWindow(AppShell)
|
||||
# This class will open a side window wich contains a scene graph and
|
||||
# a world setting page.
|
||||
#################################################################
|
||||
appversion = '1.0'
|
||||
appname = 'Navigation Window'
|
||||
frameWidth = 325
|
||||
frameHeight = 580
|
||||
frameIniPosX = 0
|
||||
frameIniPosY = 110
|
||||
padx = 0
|
||||
pady = 0
|
||||
|
||||
lightEnable = 0
|
||||
ParticleEnable = 0
|
||||
basedriveEnable = 0
|
||||
collision = 0
|
||||
backface = 0
|
||||
texture = 1
|
||||
wireframe = 0
|
||||
|
||||
enableBaseUseDrive = 0
|
||||
|
||||
def __init__(self, worldColor,lightEnable,ParticleEnable, basedriveEnable,collision,
|
||||
backface, texture, wireframe, grid, widgetVis, enableAutoCamera, parent = None, nodePath = render, **kw):
|
||||
self.worldColor = worldColor
|
||||
self.lightEnable = lightEnable
|
||||
self.ParticleEnable = ParticleEnable
|
||||
self.basedriveEnable = basedriveEnable
|
||||
self.collision = collision
|
||||
self.backface = backface
|
||||
self.texture = texture
|
||||
self.wireframe = wireframe
|
||||
self.grid = grid
|
||||
self.enableAutoCamera = enableAutoCamera
|
||||
self.widgetVis = widgetVis
|
||||
|
||||
# Define the megawidget options.
|
||||
optiondefs = (
|
||||
('title', self.appname, None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
if parent == None:
|
||||
self.parent = Toplevel()
|
||||
else:
|
||||
self.parent = parent
|
||||
|
||||
AppShell.__init__(self, self.parent)
|
||||
self.parent.geometry('%dx%d+%d+%d' % (self.frameWidth, self.frameHeight,self.frameIniPosX,self.frameIniPosY))
|
||||
|
||||
self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
|
||||
|
||||
def appInit(self):
|
||||
print '----SideWindow is Initialized!!'
|
||||
|
||||
def createInterface(self):
|
||||
# The interior of the toplevel panel
|
||||
interior = self.interior()
|
||||
mainFrame = Frame(interior)
|
||||
## Creat NoteBook
|
||||
self.notebookFrame = Pmw.NoteBook(mainFrame)
|
||||
self.notebookFrame.pack(fill=Tkinter.BOTH,expand=1)
|
||||
sgePage = self.notebookFrame.add('Tree Graph')
|
||||
envPage = self.notebookFrame.add('World Setting')
|
||||
self.notebookFrame['raisecommand'] = self.updateInfo
|
||||
|
||||
## Tree Grapgh Page
|
||||
self.SGE = seSceneGraphExplorer.seSceneGraphExplorer(
|
||||
sgePage, nodePath = render,
|
||||
scrolledCanvas_hull_width = 270,
|
||||
scrolledCanvas_hull_height = 570)
|
||||
self.SGE.pack(fill = Tkinter.BOTH, expand = 0)
|
||||
|
||||
## World Setting Page
|
||||
envPage = Frame(envPage)
|
||||
pageFrame = Frame(envPage)
|
||||
self.LightingVar = IntVar()
|
||||
self.LightingVar.set(self.lightEnable)
|
||||
self.LightingButton = Checkbutton(
|
||||
pageFrame,
|
||||
text = 'Enable Lighting',
|
||||
variable = self.LightingVar,
|
||||
command = self.toggleLights)
|
||||
self.LightingButton.pack(side=Tkinter.LEFT, expand=False)
|
||||
pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
|
||||
|
||||
pageFrame = Frame(envPage)
|
||||
self.CollisionVar = IntVar()
|
||||
self.CollisionVar.set(self.collision)
|
||||
self.CollisionButton = Checkbutton(
|
||||
pageFrame,
|
||||
text = 'Show Collision Object',
|
||||
variable = self.CollisionVar,
|
||||
command = self.showCollision)
|
||||
self.CollisionButton.pack(side=Tkinter.LEFT, expand=False)
|
||||
pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
|
||||
|
||||
pageFrame = Frame(envPage)
|
||||
self.ParticleVar = IntVar()
|
||||
self.ParticleVar.set(self.ParticleEnable)
|
||||
self.ParticleButton = Checkbutton(
|
||||
pageFrame,
|
||||
text = 'Show Particle Dummy',
|
||||
variable = self.ParticleVar,
|
||||
command = self.enableParticle)
|
||||
self.ParticleButton.pack(side=Tkinter.LEFT, expand=False)
|
||||
pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
|
||||
|
||||
pageFrame = Frame(envPage)
|
||||
self.baseUseDriveVar = IntVar()
|
||||
self.baseUseDriveVar.set(self.basedriveEnable)
|
||||
self.baseUseDriveButton = Checkbutton(
|
||||
pageFrame,
|
||||
text = 'Enable base.usedrive',
|
||||
variable = self.baseUseDriveVar,
|
||||
command = self.enablebaseUseDrive)
|
||||
self.baseUseDriveButton.pack(side=Tkinter.LEFT, expand=False)
|
||||
pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
|
||||
|
||||
pageFrame = Frame(envPage)
|
||||
self.backfaceVar = IntVar()
|
||||
self.backfaceVar.set(self.backface)
|
||||
self.backfaceButton = Checkbutton(
|
||||
pageFrame,
|
||||
text = 'Enable BackFace',
|
||||
variable = self.backfaceVar,
|
||||
command = self.toggleBackface)
|
||||
self.backfaceButton.pack(side=Tkinter.LEFT, expand=False)
|
||||
pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
|
||||
|
||||
pageFrame = Frame(envPage)
|
||||
self.textureVar = IntVar()
|
||||
self.textureVar.set(self.texture)
|
||||
self.textureButton = Checkbutton(
|
||||
pageFrame,
|
||||
text = 'Enable Texture',
|
||||
variable = self.textureVar,
|
||||
command = self.toggleTexture)
|
||||
self.textureButton.pack(side=Tkinter.LEFT, expand=False)
|
||||
pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
|
||||
|
||||
pageFrame = Frame(envPage)
|
||||
self.wireframeVar = IntVar()
|
||||
self.wireframeVar.set(self.wireframe)
|
||||
self.wireframeButton = Checkbutton(
|
||||
pageFrame,
|
||||
text = 'Enable Wireframe',
|
||||
variable = self.wireframeVar,
|
||||
command = self.toggleWireframe)
|
||||
self.wireframeButton.pack(side=Tkinter.LEFT, expand=False)
|
||||
pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
|
||||
|
||||
pageFrame = Frame(envPage)
|
||||
self.gridVar = IntVar()
|
||||
self.gridVar.set(self.grid)
|
||||
self.gridButton = Checkbutton(
|
||||
pageFrame,
|
||||
text = 'Enable Grid',
|
||||
variable = self.gridVar,
|
||||
command = self.toggleGrid)
|
||||
self.gridButton.pack(side=Tkinter.LEFT, expand=False)
|
||||
pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
|
||||
|
||||
pageFrame = Frame(envPage)
|
||||
self.widgetVisVar = IntVar()
|
||||
self.widgetVisVar.set(self.widgetVis)
|
||||
self.widgetVisButton = Checkbutton(
|
||||
pageFrame,
|
||||
text = 'Enable WidgetVisible',
|
||||
variable = self.widgetVisVar,
|
||||
command = self.togglewidgetVis)
|
||||
self.widgetVisButton.pack(side=Tkinter.LEFT, expand=False)
|
||||
pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
|
||||
|
||||
pageFrame = Frame(envPage)
|
||||
self.enableAutoCameraVar = IntVar()
|
||||
self.enableAutoCameraVar.set(self.enableAutoCamera)
|
||||
self.enableAutoCameraButton = Checkbutton(
|
||||
pageFrame,
|
||||
text = 'Enable Auto Camera Movement for Loading Objects',
|
||||
variable = self.enableAutoCameraVar,
|
||||
command = self.toggleAutoCamera)
|
||||
self.enableAutoCameraButton.pack(side=Tkinter.LEFT, expand=False)
|
||||
pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
|
||||
|
||||
pageFrame = Frame(envPage)
|
||||
self.backgroundColor = ColorEntry(
|
||||
pageFrame, text = 'BG Color', value=self.worldColor)
|
||||
self.backgroundColor['command'] = self.setBackgroundColorVec
|
||||
self.backgroundColor['resetValue'] = [0,0,0,0]
|
||||
self.backgroundColor.pack(side=Tkinter.LEFT, expand=False)
|
||||
self.bind(self.backgroundColor, 'Set background color')
|
||||
pageFrame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True)
|
||||
|
||||
envPage.pack(expand=False)
|
||||
|
||||
## Set all stuff done
|
||||
self.notebookFrame.setnaturalsize()
|
||||
mainFrame.pack(fill = 'both', expand = 1)
|
||||
|
||||
|
||||
def createMenuBar(self):
|
||||
# We don't need menu bar here.
|
||||
self.menuBar.destroy()
|
||||
|
||||
def onDestroy(self, event):
|
||||
#################################################################
|
||||
# onDestroy(self, event)
|
||||
# This function will be called when user closed the side window.
|
||||
# Here we will send out a message with whole data set we will need
|
||||
# for the next time user open the side window.
|
||||
#################################################################
|
||||
messenger.send('SW_close',[self.worldColor,
|
||||
self.lightEnable,
|
||||
self.ParticleEnable,
|
||||
self.basedriveEnable,
|
||||
self.collision,
|
||||
self.backface,
|
||||
self.texture,
|
||||
self.wireframe,
|
||||
self.grid,
|
||||
self.widgetVis,
|
||||
self.enableAutoCamera])
|
||||
'''
|
||||
If you have open any thing, please rewrite here!
|
||||
'''
|
||||
pass
|
||||
|
||||
###############################
|
||||
def updateInfo(self, page = 'Tree Graph'):
|
||||
#################################################################
|
||||
# updateInfo(self, page = 'Tree Graph')
|
||||
# This function will be called when each time user change the main
|
||||
# page of the window.
|
||||
# What it dose is to call right function to restore the data for current selected page.
|
||||
#################################################################
|
||||
if page=='Tree Graph':
|
||||
self.updateTreeGraph()
|
||||
elif page == 'World Setting':
|
||||
self.updateWorldSetting()
|
||||
|
||||
def updateTreeGraph(self):
|
||||
#################################################################
|
||||
# updateTreeGraph(self)
|
||||
# When scene graoh page has been opend, call sceneGraphExplorer to
|
||||
# updata the tree.
|
||||
#################################################################
|
||||
self.SGE.update()
|
||||
pass
|
||||
|
||||
def updateWorldSetting(self):
|
||||
#################################################################
|
||||
# updateWorldSetting(self)
|
||||
# When world setting page has been selected, this function will
|
||||
# reset those check box in the page to reflect the current world setting.
|
||||
#################################################################
|
||||
self.LightingVar.set(self.lightEnable)
|
||||
|
||||
self.CollisionVar.set(self.collision)
|
||||
self.ParticleVar.set(self.ParticleEnable)
|
||||
self.baseUseDriveVar.set(self.basedriveEnable)
|
||||
self.backgroundColor.set(value = self.worldColor)
|
||||
pass
|
||||
|
||||
def toggleLights(self):
|
||||
#################################################################
|
||||
# toggleLights(self)
|
||||
# send out a message to let sceneEditor know we need to toggle the light.
|
||||
# Then, sceneEditor will pass the message to dataHolder to disable/enable
|
||||
# the lights. (lightManager is inside the dataHolder)
|
||||
#################################################################
|
||||
self.lightEnable = (self.lightEnable+1)%2
|
||||
messenger.send('SW_lightToggle')
|
||||
pass
|
||||
|
||||
def showCollision(self):
|
||||
#################################################################
|
||||
# showCollision(self)
|
||||
# This function will send out a message to sceneEditor to toggle
|
||||
# the visibility of collision objects.
|
||||
#################################################################
|
||||
self.collision = (self.collision+1)%2
|
||||
messenger.send('SW_collisionToggle', [self.collision])
|
||||
pass
|
||||
|
||||
def enableParticle(self):
|
||||
#################################################################
|
||||
# enableParticle(self)
|
||||
# This function will send out a message to sceneEditor to toggle
|
||||
# the visibility of particle objects.
|
||||
#################################################################
|
||||
self.ParticleEnable = (self.ParticleEnable+1)%2
|
||||
messenger.send('SW_particleToggle', [self.ParticleEnable])
|
||||
pass
|
||||
|
||||
def enablebaseUseDrive(self):
|
||||
#################################################################
|
||||
# enablebaseUseDrive(self)
|
||||
# This function will toggle the usage of base.useDrive.
|
||||
# Well, it may not usefull at all.
|
||||
#
|
||||
# We won't send out any message in this time to notice
|
||||
# the sceneEditor this event happend.
|
||||
# In the other hand, we will restore it back when
|
||||
# the side window has been closed.
|
||||
#
|
||||
#################################################################
|
||||
if self.enableBaseUseDrive==0:
|
||||
print 'Enabled'
|
||||
base.useDrive()
|
||||
self.enableBaseUseDrive = 1
|
||||
else:
|
||||
print 'disabled'
|
||||
#base.useTrackball()
|
||||
base.disableMouse()
|
||||
self.enableBaseUseDrive = 0
|
||||
self.basedriveEnable = (self.basedriveEnable+1)%2
|
||||
pass
|
||||
|
||||
def toggleBackface(self):
|
||||
#################################################################
|
||||
# toggleBackface(self)
|
||||
# This function will toggle the back face setting. so it will
|
||||
# render the polygon with two sides.
|
||||
#################################################################
|
||||
base.toggleBackface()
|
||||
self.backface = (self.backface+1)%2
|
||||
return
|
||||
|
||||
def toggleBackfaceFromMainW(self):
|
||||
#################################################################
|
||||
# toggleBackfaceFromMainW(self)
|
||||
# This function is called by sceneEditor when user used hot key
|
||||
# to toggle the back face setting in the main panda window.
|
||||
# In here we will only reset the flag and reset the state of
|
||||
# check box
|
||||
#################################################################
|
||||
self.backface = (self.backface+1)%2
|
||||
self.backfaceButton.toggle()
|
||||
return
|
||||
|
||||
def toggleTexture(self):
|
||||
#################################################################
|
||||
# toggleTexture(self)
|
||||
# This function will toggle the txture using option for the whole scene.
|
||||
#################################################################
|
||||
base.toggleTexture()
|
||||
self.texture = (self.texture+1)%2
|
||||
return
|
||||
|
||||
def toggleTextureFromMainW(self):
|
||||
#################################################################
|
||||
# toggleTextureFromMainW(self)
|
||||
# This function is called by sceneEditor when user used hot key
|
||||
# to toggle the texture usage from the main panda window.
|
||||
# In here we will only reset the flag and reset the state of
|
||||
# check box
|
||||
#################################################################
|
||||
self.texture = (self.texture+1)%2
|
||||
self.textureButton.toggle()
|
||||
return
|
||||
|
||||
def toggleWireframe(self):
|
||||
#################################################################
|
||||
# toggleWireframe(self)
|
||||
# This function will toggle the wire frame mode.
|
||||
#################################################################
|
||||
base.toggleWireframe()
|
||||
self.wireframe = (self.wireframe+1)%2
|
||||
return
|
||||
|
||||
def toggleWireframeFromMainW(self):
|
||||
#################################################################
|
||||
# toggleWireframeFromMainW(self)
|
||||
# This function is called by sceneEditor when user used hot key
|
||||
# to toggle the wire frame mode in the main panda window.
|
||||
# In here we will only reset the flag and reset the state of
|
||||
# check box
|
||||
#################################################################
|
||||
self.wireframe = (self.wireframe+1)%2
|
||||
self.wireframeButton.toggle()
|
||||
return
|
||||
|
||||
def toggleGrid(self):
|
||||
#################################################################
|
||||
# toggleGrid(self)
|
||||
# This function will toggle the usage of the grid.
|
||||
#################################################################
|
||||
self.grid = (self.grid+1)%2
|
||||
if self.grid==1:
|
||||
SEditor.grid.enable()
|
||||
else:
|
||||
SEditor.grid.disable()
|
||||
|
||||
def togglewidgetVis(self):
|
||||
#################################################################
|
||||
# togglewidgetVis(self)
|
||||
# This function will toggle the visibility of the widget of the grid.
|
||||
#################################################################
|
||||
self.widgetVis = (self.widgetVis+1)%2
|
||||
SEditor.toggleWidgetVis()
|
||||
if SEditor.widget.fActive:
|
||||
messenger.send('shift-f')
|
||||
return
|
||||
|
||||
def toggleWidgetVisFromMainW(self):
|
||||
#################################################################
|
||||
# toggleWidgetVisFromMainW(self)
|
||||
# This function is called by sceneEditor when user used hot key
|
||||
# to toggle the visibility of widgets ('v') from the main panda window.
|
||||
# In here we will only reset the flag and reset the state of
|
||||
# check box
|
||||
#################################################################
|
||||
self.widgetVis = (self.widgetVis+1)%2
|
||||
self.widgetVisButton.toggle()
|
||||
return
|
||||
|
||||
def setBackgroundColorVec(self,color):
|
||||
#################################################################
|
||||
# setBackgroundColorVec(self,color)
|
||||
# Call back function
|
||||
# This will be called from the colorEntry on the world setting page.
|
||||
# The "color" here is a list containing three integer data, R, G and B.
|
||||
#################################################################
|
||||
base.setBackgroundColor(color[0]/255.0,
|
||||
color[1]/255.0,
|
||||
color[2]/255.0)
|
||||
self.worldColor = [color[0],color[1],color[2],0]
|
||||
|
||||
def toggleAutoCamera(self):
|
||||
#################################################################
|
||||
# toggleAutoCamera(self)
|
||||
# This function will toggle the usage of the auto-camera movement
|
||||
# when user loaded model or actor into the scene.
|
||||
#################################################################
|
||||
self.enableAutoCamera = (self.enableAutoCamera+1)%2
|
||||
SEditor.toggleAutoCamera()
|
||||
return
|
||||
|
||||
def selectPage(self,page='Tree Graph'):
|
||||
#################################################################
|
||||
#################################################################
|
||||
self.notebookFrame.selectpage(page)
|
||||
|
2
build/nirai/panda3d/contrib/src/sceneeditor/Sources.pp
Normal file
2
build/nirai/panda3d/contrib/src/sceneeditor/Sources.pp
Normal file
|
@ -0,0 +1,2 @@
|
|||
// For now, since we are not installing Python files, this file can
|
||||
// remain empty.
|
0
build/nirai/panda3d/contrib/src/sceneeditor/__init__.py
Normal file
0
build/nirai/panda3d/contrib/src/sceneeditor/__init__.py
Normal file
302
build/nirai/panda3d/contrib/src/sceneeditor/collisionWindow.py
Normal file
302
build/nirai/panda3d/contrib/src/sceneeditor/collisionWindow.py
Normal file
|
@ -0,0 +1,302 @@
|
|||
#################################################################
|
||||
# collisionWindow.py
|
||||
# Written by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#################################################################
|
||||
# Import Tkinter, Pmw, and the floater code from this directory tree.
|
||||
from direct.tkwidgets.AppShell import *
|
||||
from direct.showbase.TkGlobal import *
|
||||
from seColorEntry import *
|
||||
from direct.tkwidgets import VectorWidgets
|
||||
from direct.tkwidgets import Floater
|
||||
from direct.tkwidgets import Slider
|
||||
from Tkinter import *
|
||||
import string, math, types
|
||||
from pandac.PandaModules import *
|
||||
|
||||
|
||||
class collisionWindow(AppShell):
|
||||
#################################################################
|
||||
# This will open a talk window for user to set the collision object
|
||||
# In here, we won't finish the whole process to generate the
|
||||
# collision object, half of process will be finished by dataHolder.
|
||||
#################################################################
|
||||
# Override class variables
|
||||
appname = 'Creating Collision Object'
|
||||
frameWidth = 600
|
||||
frameHeight = 300
|
||||
|
||||
widgetsDict = {}
|
||||
|
||||
# Define the types of collision we take care here
|
||||
collisionType = ['collisionPolygon',
|
||||
'collisionSphere',
|
||||
'collisionSegment',
|
||||
'collisionRay']
|
||||
|
||||
def __init__(self, nodePath, parent = None, **kw):
|
||||
|
||||
self.nodePath = nodePath
|
||||
self.objType = 'collisionSphere' # set default type to Collision Sphere
|
||||
|
||||
INITOPT = Pmw.INITOPT
|
||||
optiondefs = (
|
||||
('title', self.appname, None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
# Initialize the superclass
|
||||
AppShell.__init__(self)
|
||||
|
||||
# Execute option callbacks
|
||||
self.initialiseoptions(collisionWindow)
|
||||
|
||||
self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
|
||||
|
||||
def createInterface(self):
|
||||
# Handle to the toplevels interior
|
||||
interior = self.interior()
|
||||
menuBar = self.menuBar
|
||||
self.menuBar.destroy()
|
||||
|
||||
# Create a frame to hold all stuff
|
||||
mainFrame = Frame(interior)
|
||||
|
||||
frame = Frame(mainFrame)
|
||||
|
||||
self.collisionTypeEntry = self.createcomponent(
|
||||
'Collision Type', (), None,
|
||||
Pmw.ComboBox, (frame,),
|
||||
labelpos = W, label_text='Collision Object Type:', entry_width = 20,
|
||||
selectioncommand = self.setObjectType,
|
||||
scrolledlist_items = self.collisionType)
|
||||
self.collisionTypeEntry.pack(side=LEFT, padx=3)
|
||||
|
||||
label = Label(frame, text='Parent NodePath: '+ self.nodePath.getName(), font=('MSSansSerif', 12),
|
||||
relief = RIDGE)
|
||||
label.pack(side=LEFT,expand=0,fill=X, padx=20)
|
||||
|
||||
frame.pack(side=TOP, fill=X, expand=True, padx=3)
|
||||
self.collisionTypeEntry.selectitem('collisionSphere', setentry=True)
|
||||
|
||||
self.inputZone = Pmw.Group(mainFrame, tag_pyclass = None)
|
||||
self.inputZone.pack(fill='both',expand=1)
|
||||
settingFrame = self.inputZone.interior()
|
||||
|
||||
############################################
|
||||
# Notebook pages for specific object setting
|
||||
############################################
|
||||
self.objNotebook = Pmw.NoteBook(settingFrame, tabpos = None,
|
||||
borderwidth = 0)
|
||||
PolygonPage = self.objNotebook.add('Polygon')
|
||||
SpherePage = self.objNotebook.add('Sphere')
|
||||
SegmentPage = self.objNotebook.add('Segment')
|
||||
RayPage = self.objNotebook.add('Ray')
|
||||
self.objNotebook.selectpage('Sphere')
|
||||
# Put this here so it isn't called right away
|
||||
self.objNotebook['raisecommand'] = self.updateObjInfo
|
||||
|
||||
# Polygon object setting
|
||||
|
||||
Interior = Frame(PolygonPage)
|
||||
label = Label(Interior, text='Attention! All Coordinates Are Related To Its Parent Node!')
|
||||
label.pack(side=LEFT,expand=0,fill=X, padx=1)
|
||||
Interior.pack(side=TOP, expand=0,fill=X)
|
||||
|
||||
self.createPosEntry(PolygonPage, catagory='Polygon', id='Point A')
|
||||
self.createPosEntry(PolygonPage, catagory='Polygon', id='Point B')
|
||||
self.createPosEntry(PolygonPage, catagory='Polygon', id='Point C')
|
||||
|
||||
# Sphere object setting
|
||||
|
||||
Interior = Frame(SpherePage)
|
||||
label = Label(Interior, text='Attention! All Coordinates Are Related To Its Parent Node!')
|
||||
label.pack(side=LEFT,expand=0,fill=X, padx=1)
|
||||
Interior.pack(side=TOP, expand=0,fill=X)
|
||||
|
||||
self.createPosEntry(SpherePage, catagory='Sphere', id='Center Point')
|
||||
|
||||
self.createEntryField(SpherePage,catagory='Sphere', id='Size',
|
||||
value = 1.0,
|
||||
command = None,
|
||||
initialState='normal',
|
||||
side = 'top')
|
||||
|
||||
# Segment object setting
|
||||
|
||||
Interior = Frame(SegmentPage)
|
||||
label = Label(Interior, text='Attention! All Coordinates Are Related To Its Parent Node!')
|
||||
label.pack(side=LEFT,expand=0,fill=X, padx=1)
|
||||
Interior.pack(side=TOP, expand=0,fill=X)
|
||||
|
||||
self.createPosEntry(SegmentPage, catagory='Segment', id='Point A')
|
||||
self.createPosEntry(SegmentPage, catagory='Segment', id='Point B')
|
||||
|
||||
# Ray object setting
|
||||
|
||||
Interior = Frame(RayPage)
|
||||
label = Label(Interior, text='Attention! All Coordinates Are Related To Its Parent Node!')
|
||||
label.pack(side=LEFT,expand=0,fill=X, padx=1)
|
||||
Interior.pack(side=TOP, expand=0,fill=X)
|
||||
|
||||
self.createPosEntry(RayPage, catagory='Ray', id='Origin')
|
||||
self.createPosEntry(RayPage, catagory='Ray', id='Direction')
|
||||
|
||||
|
||||
|
||||
self.objNotebook.setnaturalsize()
|
||||
self.objNotebook.pack(expand = 1, fill = BOTH)
|
||||
|
||||
self.okButton = Button(mainFrame, text="OK", command=self.okPress,width=10)
|
||||
self.okButton.pack(fill=BOTH,expand=0,side=RIGHT)
|
||||
|
||||
mainFrame.pack(expand=1, fill = BOTH)
|
||||
|
||||
def onDestroy(self, event):
|
||||
messenger.send('CW_close')
|
||||
'''
|
||||
If you have open any thing, please rewrite here!
|
||||
'''
|
||||
pass
|
||||
|
||||
def setObjectType(self, typeName = 'collisionSphere'):
|
||||
#################################################################
|
||||
# setObjectType(self, typeName = 'collisionSphere')
|
||||
# Call back function
|
||||
# This function will be called when user select target collision
|
||||
# type on the combo box on the panel.
|
||||
# Basically, this function's job is to switch the notebook page to right one.
|
||||
#################################################################
|
||||
self.objType = typeName
|
||||
if self.objType=='collisionPolygon':
|
||||
self.objNotebook.selectpage('Polygon')
|
||||
elif self.objType=='collisionSphere':
|
||||
self.objNotebook.selectpage('Sphere')
|
||||
elif self.objType=='collisionSegment':
|
||||
self.objNotebook.selectpage('Segment')
|
||||
elif self.objType=='collisionRay':
|
||||
self.objNotebook.selectpage('Ray')
|
||||
|
||||
return
|
||||
|
||||
def updateObjInfo(self, page=None):
|
||||
#################################################################
|
||||
# Nothing. Unlike in the lighting panel, we don't have to keep data
|
||||
# once user switch the page.
|
||||
#################################################################
|
||||
return
|
||||
|
||||
def okPress(self):
|
||||
#################################################################
|
||||
# okPress(self)
|
||||
# This function will be called when user click on the Ok button.
|
||||
# Then this function will collect all parameters that we need to create
|
||||
# a collision Object from the panel and generate the colision Object.
|
||||
# In the last, it will send the object out with a message to dataHolder to
|
||||
# put the object into a CollisionNode and attach it to the target nodePath
|
||||
#################################################################
|
||||
collisionObject = None
|
||||
print self.objType
|
||||
if self.objType=='collisionPolygon':
|
||||
pointA = Point3(float(self.widgetDict['PolygonPoint A'][0]._entry.get()),
|
||||
float(self.widgetDict['PolygonPoint A'][1]._entry.get()),
|
||||
float(self.widgetDict['PolygonPoint A'][2]._entry.get()))
|
||||
pointB = Point3(float(self.widgetDict['PolygonPoint B'][0]._entry.get()),
|
||||
float(self.widgetDict['PolygonPoint B'][1]._entry.get()),
|
||||
float(self.widgetDict['PolygonPoint B'][2]._entry.get()))
|
||||
pointC = Point3(float(self.widgetDict['PolygonPoint C'][0]._entry.get()),
|
||||
float(self.widgetDict['PolygonPoint C'][1]._entry.get()),
|
||||
float(self.widgetDict['PolygonPoint C'][2]._entry.get()))
|
||||
collisionObject = CollisionPolygon(pointA, pointB, pointC)
|
||||
|
||||
elif self.objType=='collisionSphere':
|
||||
collisionObject = CollisionSphere(float(self.widgetDict['SphereCenter Point'][0]._entry.get()),
|
||||
float(self.widgetDict['SphereCenter Point'][1]._entry.get()),
|
||||
float(self.widgetDict['SphereCenter Point'][2]._entry.get()),
|
||||
float(self.widgetDict['SphereSize'].getvalue()))
|
||||
|
||||
elif self.objType=='collisionSegment':
|
||||
pointA = Point3(float(self.widgetDict['SegmentPoint A'][0]._entry.get()),
|
||||
float(self.widgetDict['SegmentPoint A'][1]._entry.get()),
|
||||
float(self.widgetDict['SegmentPoint A'][2]._entry.get()))
|
||||
pointB = Point3(float(self.widgetDict['SegmentPoint B'][0]._entry.get()),
|
||||
float(self.widgetDict['SegmentPoint B'][1]._entry.get()),
|
||||
float(self.widgetDict['SegmentPoint B'][2]._entry.get()))
|
||||
|
||||
collisionObject = CollisionSegment()
|
||||
collisionObject.setPointA(pointA)
|
||||
collisionObject.setFromLens(base.cam.node(), Point2( -1, 1 )) ## You must set up the camera lensNode before you set point B....
|
||||
collisionObject.setPointB(pointB)
|
||||
|
||||
elif self.objType=='collisionRay':
|
||||
point = Point3(float(self.widgetDict['RayOrigin'][0]._entry.get()),
|
||||
float(self.widgetDict['RayOrigin'][1]._entry.get()),
|
||||
float(self.widgetDict['RayOrigin'][2]._entry.get()))
|
||||
|
||||
vector = Vec3(float(self.widgetDict['RayDirection'][0]._entry.get()),
|
||||
float(self.widgetDict['RayDirection'][1]._entry.get()),
|
||||
float(self.widgetDict['RayDirection'][2]._entry.get()))
|
||||
|
||||
print vector, point
|
||||
|
||||
collisionObject = CollisionRay()
|
||||
collisionObject.setOrigin(point)
|
||||
collisionObject.setDirection(vector)
|
||||
#collisionObject.setFromLens(base.cam.node(), Point2( -1, 1 )) ## You must set up the camera lensNode before you set up others...
|
||||
|
||||
if self.objType=='collisionPolygon':
|
||||
messenger.send('CW_addCollisionObj', [collisionObject, self.nodePath, pointA, pointB, pointC])
|
||||
else:
|
||||
messenger.send('CW_addCollisionObj', [collisionObject, self.nodePath])
|
||||
|
||||
self.quit()
|
||||
|
||||
return
|
||||
|
||||
def createPosEntry(self, contentFrame, catagory, id):
|
||||
posInterior = Frame(contentFrame)
|
||||
label = Label(posInterior, text=id+':')
|
||||
label.pack(side=LEFT,expand=0,fill=X, padx=1)
|
||||
self.posX = self.createcomponent('posX'+catagory+id, (), None,
|
||||
Floater.Floater, (posInterior,),
|
||||
text = 'X', relief = FLAT,
|
||||
value = 0.0,
|
||||
entry_width = 6)
|
||||
|
||||
self.posX.pack(side=LEFT,expand=0,fill=X, padx=1)
|
||||
|
||||
self.posY = self.createcomponent('posY'+catagory+id, (), None,
|
||||
Floater.Floater, (posInterior,),
|
||||
text = 'Y', relief = FLAT,
|
||||
value = 0.0,
|
||||
entry_width = 6)
|
||||
self.posY.pack(side=LEFT, expand=0,fill=X, padx=1)
|
||||
|
||||
self.posZ = self.createcomponent('posZ'+catagory+id, (), None,
|
||||
Floater.Floater, (posInterior,),
|
||||
text = 'Z', relief = FLAT,
|
||||
value = 0.0,
|
||||
entry_width = 6)
|
||||
self.posZ.pack(side=LEFT, expand=0,fill=X, padx=1)
|
||||
self.widgetDict[catagory+id]=[self.posX, self.posY, self.posZ]
|
||||
posInterior.pack(side=TOP, expand=0,fill=X, padx=3, pady=3)
|
||||
return
|
||||
|
||||
def createEntryField(self, parent, catagory, id, value,
|
||||
command, initialState, labelWidth = 6,
|
||||
side = 'left', fill = X, expand = 0,
|
||||
validate = None,
|
||||
defaultButton = False, buttonText = 'Default',defaultFunction = None ):
|
||||
frame = Frame(parent)
|
||||
widget = Pmw.EntryField(frame, labelpos='w', label_text = id+':',
|
||||
value = value, entry_font=('MSSansSerif', 10),label_font=('MSSansSerif', 10),
|
||||
modifiedcommand=command, validate = validate,
|
||||
label_width = labelWidth)
|
||||
widget.configure(entry_state = initialState)
|
||||
widget.pack(side=LEFT)
|
||||
self.widgetDict[catagory+id] = widget
|
||||
if defaultButton and (defaultFunction!=None):
|
||||
widget = Button(frame, text=buttonText, font=('MSSansSerif', 10), command = defaultFunction)
|
||||
widget.pack(side=LEFT, padx=3)
|
||||
self.widgetDict[catagory+id+'-'+'DefaultButton']=widget
|
||||
|
||||
frame.pack(side = side, fill = fill, expand = expand,pady=3)
|
695
build/nirai/panda3d/contrib/src/sceneeditor/controllerWindow.py
Normal file
695
build/nirai/panda3d/contrib/src/sceneeditor/controllerWindow.py
Normal file
|
@ -0,0 +1,695 @@
|
|||
#################################################################
|
||||
# controllerWindow.py
|
||||
# Written by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#################################################################
|
||||
|
||||
from direct.tkwidgets.AppShell import AppShell
|
||||
from Tkinter import Frame, Label, Button
|
||||
import string, Pmw, Tkinter
|
||||
|
||||
# Define the Category
|
||||
KEYBOARD = 'Keyboard-'
|
||||
TRACKER = 'Tarcker-'
|
||||
|
||||
class controllerWindow(AppShell):
|
||||
#################################################################
|
||||
# This will open a talk window for user to set the control mechanism
|
||||
# In here, user can choose to control what object by keyboard or other inputs.
|
||||
#################################################################
|
||||
|
||||
# Override class variables
|
||||
appname = 'Controller Panel'
|
||||
frameWidth = 500
|
||||
frameHeight = 500
|
||||
|
||||
widgetsDict = {} # category-id : widget obj
|
||||
|
||||
# setup the type of controller we handle here.
|
||||
controllerList = ['Keyboard',
|
||||
'Tracker']
|
||||
|
||||
# Default Keyboard setting
|
||||
keyboardMapDict = {}
|
||||
keyboardSpeedDict = {}
|
||||
|
||||
def __init__(self, listOfObj, controlType , dataList, parent = None, **kw):
|
||||
if controlType == 'Keyboard':
|
||||
self.nodePath = dataList[0] # Default setting -> mainly used for Keyboard control now.
|
||||
self.nameOfNode = self.nodePath.getName()
|
||||
self.controllType = 'Keyboard'
|
||||
self.keyboardMapDict.clear()
|
||||
self.keyboardMapDict = dataList[1]
|
||||
self.keyboardSpeedDict.clear()
|
||||
self.keyboardSpeedDict = dataList[2]
|
||||
|
||||
self.listOfObj = listOfObj
|
||||
self.keepControl = False
|
||||
|
||||
INITOPT = Pmw.INITOPT
|
||||
optiondefs = (
|
||||
('title', self.appname, None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
# Initialize the superclass
|
||||
AppShell.__init__(self)
|
||||
|
||||
# Execute option callbacks
|
||||
self.initialiseoptions(controllerWindow)
|
||||
|
||||
self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
|
||||
|
||||
def createInterface(self):
|
||||
# Handle to the toplevels interior
|
||||
interior = self.interior()
|
||||
menuBar = self.menuBar
|
||||
|
||||
# We don't need menu bar here
|
||||
self.menuBar.destroy()
|
||||
|
||||
# Create a frame to hold all stuff
|
||||
mainFrame = Frame(interior)
|
||||
|
||||
# A comboBox to switch the controller
|
||||
frame = Frame(mainFrame)
|
||||
self.cotrollerTypeEntry = self.createcomponent(
|
||||
'Controller Type', (), None,
|
||||
Pmw.ComboBox, (frame,),
|
||||
labelpos = Tkinter.W, label_text='Controller Type:', entry_width = 20,entry_state = Tkinter.DISABLED,
|
||||
selectioncommand = self.setControllerType,
|
||||
scrolledlist_items = self.controllerList)
|
||||
self.cotrollerTypeEntry.pack(side=Tkinter.LEFT)
|
||||
frame.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=False, pady = 3)
|
||||
self.cotrollerTypeEntry.selectitem('Keyboard', setentry=True)
|
||||
|
||||
self.inputZone = Pmw.Group(mainFrame, tag_pyclass = None)
|
||||
self.inputZone.pack(fill='both',expand=1)
|
||||
settingFrame = self.inputZone.interior()
|
||||
|
||||
###################################################
|
||||
# Notebook pages for specific controller setting #
|
||||
###################################################
|
||||
self.contentWidge = self.createcomponent(
|
||||
'scrolledFrame',
|
||||
(), None,
|
||||
Pmw.ScrolledFrame, (settingFrame,),
|
||||
hull_width = 200, hull_height = 300,
|
||||
usehullsize = 1)
|
||||
self.contentFrame = self.contentWidge.component('frame')
|
||||
self.contentWidge.pack(fill = 'both', expand = 1,padx = 3, pady = 5)
|
||||
self.objNotebook = Pmw.NoteBook(self.contentFrame, tabpos = None,
|
||||
borderwidth = 0)
|
||||
keyboardPage = self.objNotebook.add('Keyboard')
|
||||
tarckerPage = self.objNotebook.add('Tracker')
|
||||
self.objNotebook.selectpage('Keyboard')
|
||||
self.objNotebook.pack(side = Tkinter.TOP, fill='both',expand=False)
|
||||
# Put this here so it isn't called right away
|
||||
self.objNotebook['raisecommand'] = self.updateControlInfo
|
||||
|
||||
# Keyboard setting
|
||||
assignFrame = Frame(keyboardPage)
|
||||
|
||||
Interior = Frame(assignFrame)
|
||||
widget = self.createcomponent(
|
||||
'Target Type', (), None,
|
||||
Pmw.ComboBox, (Interior,),
|
||||
labelpos = Tkinter.W, label_text='Target Object:', entry_width = 20, entry_state = Tkinter.DISABLED,
|
||||
selectioncommand = self.setTargetObj,
|
||||
scrolledlist_items = self.listOfObj)
|
||||
widget.pack(side=Tkinter.LEFT, padx=3)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 5)
|
||||
widget.selectitem(self.nameOfNode, setentry=True)
|
||||
self.widgetsDict[KEYBOARD+'ObjList'] = widget
|
||||
|
||||
inputZone = Pmw.Group(assignFrame, tag_pyclass = None)
|
||||
inputZone.pack(fill='both',expand=1)
|
||||
settingFrame = inputZone.interior()
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Assign a Key For:').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True,pady = 6 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Forward :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Forward key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyForward'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyForward'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Forward Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedForward'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedForward'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Backward :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Backward key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyBackward'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyBackward'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Backward Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedBackward'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedBackward'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Right :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Right key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyRight'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyRight'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Right Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedRight'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedRight'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Left :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Left key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyLeft'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyLeft'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Left Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedLeft'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedLeft'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Up :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Up key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyUp'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyUp'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Up Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedUp'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedUp'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Down :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Down key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyDown'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyDown'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Down Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedDown'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedDown'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Turn Right:', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Turn Right key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyTurnRight'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyTurnRight'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Turn Right Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedTurnRight'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedTurnRight'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Turn Left :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Turn Left key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyTurnLeft'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyTurnLeft'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Turn Left Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedTurnLeft'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedTurnLeft'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Turn UP :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Turn UP key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyTurnUp'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyTurnUp'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Turn UP Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedTurnUp'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedTurnUp'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Turn Down :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Turn Down key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyTurnDown'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyTurnDown'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Turn Down Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedTurnDown'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedTurnDown'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Roll Right:', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Roll Right key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyRollRight'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyRollRight'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Roll Right Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedRollRight'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedRollRight'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Roll Left :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Roll Left key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyRollLeft'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyRollLeft'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Roll Left Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedRollLeft'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedRollLeft'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Scale UP :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale UP key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyScaleUp'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyScaleUp'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale UP Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedScaleUp'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedScaleUp'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Scale Down:', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale Down key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyScaleDown'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyScaleDown'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale Down Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedScaleDown'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedScaleDown'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Scale X UP :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale X UP key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyScaleXUp'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyScaleXUp'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale X UP Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedScaleXUp'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedScaleXUp'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Scale X Down:', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale X Down key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyScaleXDown'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyScaleXDown'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale Down X Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedScaleXDown'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedScaleXDown'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Scale Y UP :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale Y UP key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyScaleYUp'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyScaleYUp'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale Y UP Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedScaleYUp'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedScaleYUp'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Scale Y Down:', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale Y Down key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyScaleYDown'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyScaleYDown'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale Down XY Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedScaleYDown'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedScaleYDown'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Scale Z UP :', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale Z UP key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyScaleZUp'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyScaleZUp'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale Z UP Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedScaleZUp'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedScaleZUp'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
Interior = Frame(settingFrame)
|
||||
widget = Label(Interior, text = 'Scale Z Down:', width = 20, anchor = Tkinter.W).pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale Z Down key', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardMapDict['KeyScaleZDown'],
|
||||
labelpos = Tkinter.W, label_text='Key :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'KeyScaleZDown'] = widget
|
||||
widget = Label(Interior, text = ' ').pack(side=Tkinter.LEFT, expand = False)
|
||||
widget = self.createcomponent(
|
||||
'Scale Down Z Speed', (), None,
|
||||
Pmw.EntryField, (Interior,),
|
||||
value = self.keyboardSpeedDict['SpeedScaleZDown'],
|
||||
labelpos = Tkinter.W, label_text='Speed :', entry_width = 10)
|
||||
widget.pack(side=Tkinter.LEFT, expand = False)
|
||||
self.widgetsDict[KEYBOARD+'SpeedScaleZDown'] = widget
|
||||
widget = Label(Interior, text = 'Per Second').pack(side=Tkinter.LEFT, expand = False)
|
||||
Interior.pack(side=Tkinter.TOP, fill=Tkinter.X, expand=True, pady = 4 )
|
||||
|
||||
assignFrame.pack(side=Tkinter.TOP, expand=True, fill = Tkinter.X)
|
||||
keyboardPage.pack(side=Tkinter.TOP, expand=True, fill = Tkinter.X)
|
||||
|
||||
####################################################################
|
||||
####################################################################
|
||||
# End of Keyboard control page
|
||||
####################################################################
|
||||
####################################################################
|
||||
# Pack the mainFrame
|
||||
frame = Frame(mainFrame)
|
||||
widget = Button(frame, text='OK', width = 13, command=self.ok_press).pack(side=Tkinter.RIGHT)
|
||||
widget = Button(frame, text='Enable Control', width = 13, command=self.enableControl).pack(side=Tkinter.LEFT)
|
||||
widget = Button(frame, text='Disable Control', width = 13, command=self.disableControl).pack(side=Tkinter.LEFT)
|
||||
widget = Button(frame, text='Save & Keep', width = 13, command=self.saveKeepControl).pack(side=Tkinter.LEFT)
|
||||
frame.pack(side = Tkinter.BOTTOM, expand=1, fill = Tkinter.X)
|
||||
mainFrame.pack(expand=1, fill = Tkinter.BOTH)
|
||||
|
||||
def onDestroy(self, event):
|
||||
# Check if user wish to keep the control after the window closed.
|
||||
if not self.keepControl:
|
||||
messenger.send('ControlW_controlDisable',[self.controllType])
|
||||
messenger.send('ControlW_close')
|
||||
'''
|
||||
If you have open any thing, please rewrite here!
|
||||
'''
|
||||
pass
|
||||
|
||||
def ok_press(self):
|
||||
####################################################################
|
||||
# ok_press(self)
|
||||
# After user clicked on "OK" button, this function will be called.
|
||||
# This function will collect data from the panel and send it back to
|
||||
# sceneEditor and close the window. It won't activate control at all.
|
||||
####################################################################
|
||||
if self.controllType=='Keyboard':
|
||||
for index in self.keyboardMapDict:
|
||||
self.keyboardMapDict[index] = self.widgetsDict['Keyboard-'+index].getvalue()
|
||||
for index in self.keyboardSpeedDict:
|
||||
self.keyboardSpeedDict[index] = float(self.widgetsDict['Keyboard-'+index].getvalue())
|
||||
messenger.send('ControlW_controlSetting', ['Keyboard', [self.nodePath, self.keyboardMapDict, self.keyboardSpeedDict]])
|
||||
self.quit()
|
||||
return
|
||||
|
||||
def enableControl(self):
|
||||
####################################################################
|
||||
# enableControl(self)
|
||||
# Call back function.
|
||||
# THis function will be called each time when user clicks on the
|
||||
# "Enable Control" button. This function will do pretty much
|
||||
# the same thing with ok_press function, except that this function
|
||||
# will activate the control process in sceneEditor.
|
||||
# However, if user didn't click on the button "Keep ANd Save,"
|
||||
# the control process will be terminated when user closed the panel.
|
||||
####################################################################
|
||||
if self.controllType=='Keyboard':
|
||||
for index in self.keyboardMapDict:
|
||||
self.keyboardMapDict[index] = self.widgetsDict['Keyboard-'+index].getvalue()
|
||||
for index in self.keyboardSpeedDict:
|
||||
self.keyboardSpeedDict[index] = float(self.widgetsDict['Keyboard-'+index].getvalue())
|
||||
messenger.send('ControlW_controlEnable', ['Keyboard', [self.nodePath, self.keyboardMapDict, self.keyboardSpeedDict]])
|
||||
return
|
||||
|
||||
def disableControl(self):
|
||||
####################################################################
|
||||
# disableControl(self)
|
||||
# This function will send out a message to sceneEditor to stop the
|
||||
# control task.
|
||||
####################################################################
|
||||
messenger.send('ControlW_controlDisable',[self.controllType])
|
||||
return
|
||||
|
||||
def setControllerType(self, typeName = 'Keyboard'):
|
||||
#################################################################
|
||||
# setControllerType(self, typeName = 'Keyboard')
|
||||
# Call back function
|
||||
# This function will be called when user select the type of
|
||||
# controller they want on the combo box on the panel.
|
||||
# Basically, this function's job is to switch the notebook page to right one.
|
||||
#################################################################
|
||||
self.controllType = typeName
|
||||
if self.controllType=='Keyboard':
|
||||
self.objNotebook.selectpage('Keyboard')
|
||||
elif self.controllType=='Tracker':
|
||||
self.objNotebook.selectpage('Tracker')
|
||||
|
||||
return
|
||||
|
||||
def updateControlInfo(self, page=None):
|
||||
#################################################################
|
||||
# Nothing. Unlike in the lighting panel, we don't have to keep data
|
||||
# once user switch the page.
|
||||
#################################################################
|
||||
return
|
||||
|
||||
def setTargetObj(self, name = None, tracker = None):
|
||||
#################################################################
|
||||
# setTargetObj(self, name = None)
|
||||
# setup the target object we want to control
|
||||
#################################################################
|
||||
if tracker == None: # Call from Keyboard page.
|
||||
if name=='camera':
|
||||
self.nodePath = camera
|
||||
else:
|
||||
messenger.send('ControlW_require',[name])
|
||||
return
|
||||
|
||||
def resetNameList(self, list, name = None, nodePath = None):
|
||||
####################################################################
|
||||
# resetNameList(self, list, name = None, nodePath = None)
|
||||
# This function will be called be sceneEditor in order to reset the
|
||||
# object list inside the panel.
|
||||
# list here is a name list for all objects that can be set on control
|
||||
# in the scene. If user has specify a name and a nodePath in, it will
|
||||
# check if the name is equal to the name of current control target.
|
||||
# If so, it will change the name showed on panel.
|
||||
####################################################################
|
||||
self.widgetsDict['Keyboard-ObjList'].setlist(list)
|
||||
if name != None:
|
||||
if self.nameOfNode == name:
|
||||
self.nameOfNode = self.nodePath.getName()
|
||||
self.widgetsDict['Keyboard-ObjList'].selectitem(self.nameOfNode, setentry=True)
|
||||
return
|
||||
|
||||
def setNodePathIn(self, nodePath):
|
||||
####################################################################
|
||||
# setNodePathIn(self, nodePath)
|
||||
# THis function will be called by sceneEditor.
|
||||
# After we send out a message to sceneEditor in setTargetObj function,
|
||||
# This function will be called by sceneEditor after we get the reference
|
||||
# of target object from dataHolder.
|
||||
# This function will keep the reference.
|
||||
####################################################################
|
||||
self.nodePath = nodePath
|
||||
self.nameOfNode = self.nodePath.getName()
|
||||
return
|
||||
|
||||
def saveKeepControl(self):
|
||||
#################################################################
|
||||
# saveKeepControl(self)
|
||||
# When any time user has click on the "Save & Keep" button,
|
||||
# This function will be called.
|
||||
# This function will send out the message to sceneEditor to process
|
||||
# the saving. Also, this function will change the "self.keepControl" flag.
|
||||
# So, when user closes the window with control enabled, it will keep
|
||||
# the control process runnning. otherwise program will disable the
|
||||
# control automatically when panel has been closed.
|
||||
#
|
||||
# It doesn't mean that this function will automatically enable the
|
||||
# control when user closed the window!!
|
||||
# This flag will only decide that we will send out a "stopControl"
|
||||
# message or not.
|
||||
#
|
||||
#################################################################
|
||||
self.keepControl = True
|
||||
if self.controllType=='Keyboard':
|
||||
for index in self.keyboardMapDict:
|
||||
self.keyboardMapDict[index] = self.widgetsDict['Keyboard-'+index].getvalue()
|
||||
for index in self.keyboardSpeedDict:
|
||||
self.keyboardSpeedDict[index] = float(self.widgetsDict['Keyboard-'+index].getvalue())
|
||||
print self.nodePath
|
||||
messenger.send('ControlW_saveSetting', ['Keyboard', [self.nodePath, self.keyboardMapDict, self.keyboardSpeedDict]])
|
||||
return
|
||||
|
||||
|
1071
build/nirai/panda3d/contrib/src/sceneeditor/dataHolder.py
Normal file
1071
build/nirai/panda3d/contrib/src/sceneeditor/dataHolder.py
Normal file
File diff suppressed because it is too large
Load diff
172
build/nirai/panda3d/contrib/src/sceneeditor/duplicateWindow.py
Normal file
172
build/nirai/panda3d/contrib/src/sceneeditor/duplicateWindow.py
Normal file
|
@ -0,0 +1,172 @@
|
|||
#################################################################
|
||||
# duplicateWindow.py
|
||||
# Written by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#################################################################
|
||||
from direct.tkwidgets.AppShell import *
|
||||
from direct.showbase.TkGlobal import *
|
||||
|
||||
import seSceneGraphExplorer
|
||||
|
||||
|
||||
class duplicateWindow(AppShell):
|
||||
#################################################################
|
||||
# duplicateWindow(AppShell)
|
||||
# This class is used to create a dialog window
|
||||
# for handling the "dupicate" command from the sceneEditor
|
||||
#
|
||||
# Notice!
|
||||
# The actual duplicating process is not happending here!
|
||||
# The one handle the process is dataHolder...
|
||||
#################################################################
|
||||
appversion = '1.0'
|
||||
appname = 'Duplication'
|
||||
frameWidth = 450
|
||||
frameHeight = 320
|
||||
frameIniPosX = 250
|
||||
frameIniPosY = 250
|
||||
padx = 0
|
||||
pady = 0
|
||||
|
||||
|
||||
def __init__(self, parent = None, nodePath = None, **kw):
|
||||
# Define the megawidget options.
|
||||
optiondefs = (
|
||||
('title', self.appname, None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
if parent == None:
|
||||
self.parent = Toplevel()
|
||||
AppShell.__init__(self, self.parent)
|
||||
self.parent.geometry('%dx%d+%d+%d' % (self.frameWidth, self.frameHeight,self.frameIniPosX,self.frameIniPosY))
|
||||
|
||||
self.nodePath = nodePath
|
||||
|
||||
self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
|
||||
|
||||
def appInit(self):
|
||||
print '----SideWindow is Initialized!!'
|
||||
|
||||
def createInterface(self):
|
||||
# The interior of the toplevel panel
|
||||
interior = self.interior()
|
||||
mainFrame = Frame(interior)
|
||||
self.inputZone = Pmw.Group(mainFrame, tag_text='Offset setting')
|
||||
self.inputZone.pack(fill='both',expand=1)
|
||||
settingFrame = self.inputZone.interior()
|
||||
Label(settingFrame,text=' X ').place(anchor=NW,x=110,y=15)
|
||||
Label(settingFrame,text=' Y ').place(anchor=NW,x=205,y=15)
|
||||
Label(settingFrame,text=' Z ').place(anchor=NW,x=295,y=15)
|
||||
self.move_x = Pmw.EntryField(settingFrame,label_text='Move :',labelpos='w',value='0.0', validate=Pmw.realvalidator)
|
||||
self.move_x.component('entry').config(width=10)
|
||||
self.move_y = Pmw.EntryField(settingFrame,value='0.0', validate=Pmw.realvalidator)
|
||||
self.move_y.component('entry').config(width=10)
|
||||
self.move_z = Pmw.EntryField(settingFrame, value='0.0', validate=Pmw.realvalidator)
|
||||
self.move_z.component('entry').config(width=10)
|
||||
self.move_x.place(anchor=NW,x=50,y=40)
|
||||
self.move_y.place(anchor=NW,x=185,y=40)
|
||||
self.move_z.place(anchor=NW,x=275,y=40)
|
||||
|
||||
self.rotate_x = Pmw.EntryField(settingFrame,label_text='Rotate:',labelpos='w',value='0.0', validate=Pmw.realvalidator)
|
||||
self.rotate_x.component('entry').config(width=10)
|
||||
self.rotate_y = Pmw.EntryField(settingFrame,value='0.0', validate=Pmw.realvalidator)
|
||||
self.rotate_y.component('entry').config(width=10)
|
||||
self.rotate_z = Pmw.EntryField(settingFrame, value='0.0', validate=Pmw.realvalidator)
|
||||
self.rotate_z.component('entry').config(width=10)
|
||||
self.rotate_x.place(anchor=NW,x=50,y=70)
|
||||
self.rotate_y.place(anchor=NW,x=185,y=70)
|
||||
self.rotate_z.place(anchor=NW,x=275,y=70)
|
||||
|
||||
self.scale_x = Pmw.EntryField(settingFrame,label_text='Scale :',labelpos='w',value='1.0', validate=Pmw.realvalidator)
|
||||
self.scale_x.component('entry').config(width=10)
|
||||
self.scale_y = Pmw.EntryField(settingFrame,value='1.0', validate=Pmw.realvalidator)
|
||||
self.scale_y.component('entry').config(width=10)
|
||||
self.scale_z = Pmw.EntryField(settingFrame, value='1.0', validate=Pmw.realvalidator)
|
||||
self.scale_z.component('entry').config(width=10)
|
||||
self.scale_x.place(anchor=NW,x=52,y=100)
|
||||
self.scale_y.place(anchor=NW,x=185,y=100)
|
||||
self.scale_z.place(anchor=NW,x=275,y=100)
|
||||
|
||||
self.numberOfCopy = Pmw.EntryField(settingFrame,label_text='Number of Copy :',labelpos='w',value='1', validate=Pmw.integervalidator)
|
||||
self.numberOfCopy.component('entry').config(width=15)
|
||||
self.numberOfCopy.place(anchor=NW,x=52,y=150)
|
||||
|
||||
settingFrame.pack(fill=BOTH,expand=1,padx=7,pady=7)
|
||||
|
||||
self.button_ok = Button(mainFrame, text="OK", command=self.ok_press,width=10)
|
||||
self.button_ok.pack(fill=BOTH,expand=0,side=RIGHT)
|
||||
|
||||
mainFrame.pack(fill = 'both', expand = 1,padx=7,pady=7)
|
||||
|
||||
|
||||
def createMenuBar(self):
|
||||
self.menuBar.destroy()
|
||||
|
||||
def onDestroy(self, event):
|
||||
messenger.send('DW_close')
|
||||
'''
|
||||
If you have open any thing, please rewrite here!
|
||||
'''
|
||||
pass
|
||||
|
||||
###############################
|
||||
|
||||
def ok_press(self):
|
||||
#################################################################
|
||||
# ok_press(self)
|
||||
# Callback function
|
||||
# This function will be called when user click on the "OK" button on the window.
|
||||
# After collect all data we need for the duplication process,
|
||||
# this function will send out a message with all data.
|
||||
# 'DW_duplicating'
|
||||
# This message will be caught by sceneEditor.
|
||||
#################################################################
|
||||
if not self.allEntryValid():
|
||||
print '---- Duplication Window: Invalid value!!'
|
||||
return
|
||||
x = self.move_x.getvalue()
|
||||
y = self.move_y.getvalue()
|
||||
z = self.move_z.getvalue()
|
||||
pos=Vec3(FloatType(x),FloatType(y),FloatType(z))
|
||||
x = self.rotate_x.getvalue()
|
||||
y = self.rotate_y.getvalue()
|
||||
z = self.rotate_z.getvalue()
|
||||
hpr=Vec3(FloatType(x),FloatType(y),FloatType(z))
|
||||
x = self.scale_x.getvalue()
|
||||
y = self.scale_y.getvalue()
|
||||
z = self.scale_z.getvalue()
|
||||
scale=Vec3(FloatType(x),FloatType(y),FloatType(z))
|
||||
num = int(self.numberOfCopy.getvalue())
|
||||
messenger.send('DW_duplicating',[self.nodePath,pos,hpr,scale,num])
|
||||
self.quit()
|
||||
|
||||
def allEntryValid(self):
|
||||
#################################################################
|
||||
# allEntryValid(self)
|
||||
# This function is used to check all data in the input entries are valid.
|
||||
#
|
||||
# For example, none of entries contains blank data.
|
||||
#
|
||||
#################################################################
|
||||
if not self.move_x.valid():
|
||||
return False
|
||||
elif not self.move_y.valid():
|
||||
return False
|
||||
elif not self.move_z.valid():
|
||||
return False
|
||||
elif not self.rotate_x.valid():
|
||||
return False
|
||||
elif not self.rotate_y.valid():
|
||||
return False
|
||||
elif not self.rotate_z.valid():
|
||||
return False
|
||||
elif not self.scale_x.valid():
|
||||
return False
|
||||
elif not self.scale_y.valid():
|
||||
return False
|
||||
elif not self.scale_z.valid():
|
||||
return False
|
||||
elif not self.numberOfCopy.valid():
|
||||
return False
|
||||
|
||||
return True
|
493
build/nirai/panda3d/contrib/src/sceneeditor/lightingPanel.py
Normal file
493
build/nirai/panda3d/contrib/src/sceneeditor/lightingPanel.py
Normal file
|
@ -0,0 +1,493 @@
|
|||
#################################################################
|
||||
# lightingPanel.py
|
||||
# Written by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#################################################################
|
||||
# Import Tkinter, Pmw, and the floater code from this directory tree.
|
||||
from direct.tkwidgets.AppShell import AppShell
|
||||
from seColorEntry import *
|
||||
from direct.tkwidgets.VectorWidgets import Vector3Entry
|
||||
from direct.tkwidgets.Slider import Slider
|
||||
from Tkinter import Frame, Button, Menubutton, Menu
|
||||
import string, math, types, Pmw, Tkinter
|
||||
from pandac.PandaModules import *
|
||||
|
||||
class lightingPanel(AppShell):
|
||||
#################################################################
|
||||
# lightingPanel(AppShell)
|
||||
# This will create a window to let user
|
||||
# create any kinds of lighting into the scene
|
||||
#################################################################
|
||||
# Override class variables
|
||||
appname = 'Lighting Panel'
|
||||
frameWidth = 400
|
||||
frameHeight = 400
|
||||
currentLight = None
|
||||
|
||||
def __init__(self, lightList, parent = None, **kw):
|
||||
self.lightList = lightList
|
||||
self.lightColor = [0.3*255,0.3*255,0.3*255]
|
||||
self.type = ''
|
||||
INITOPT = Pmw.INITOPT
|
||||
optiondefs = (
|
||||
('title', self.appname, None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
# Initialize the superclass
|
||||
AppShell.__init__(self)
|
||||
|
||||
# Execute option callbacks
|
||||
self.initialiseoptions(lightingPanel)
|
||||
|
||||
self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
|
||||
|
||||
def createInterface(self):
|
||||
# Handle to the toplevels interior
|
||||
interior = self.interior()
|
||||
menuBar = self.menuBar
|
||||
self.menuBar.destroy()
|
||||
|
||||
# Create a frame to hold all stuff
|
||||
mainFrame = Frame(interior)
|
||||
|
||||
self.listZone = Pmw.Group(mainFrame,tag_pyclass = None)
|
||||
self.listZone.pack(expand=0, fill=Tkinter.X,padx=3,pady=3)
|
||||
listFrame = self.listZone.interior()
|
||||
|
||||
self.lightEntry = self.createcomponent(
|
||||
'Lights List', (), None,
|
||||
Pmw.ComboBox, (listFrame,),label_text='Light :',
|
||||
labelpos = Tkinter.W, entry_width = 25, selectioncommand = self.selectLight,
|
||||
scrolledlist_items = self.lightList)
|
||||
self.lightEntry.pack(side=Tkinter.LEFT)
|
||||
|
||||
self.renameButton = self.createcomponent(
|
||||
'Rename Light', (), None,
|
||||
Button, (listFrame,),
|
||||
text = ' Rename ',
|
||||
command = self.renameLight)
|
||||
self.renameButton.pack(side=Tkinter.LEFT)
|
||||
|
||||
self.addLighZone = Pmw.Group(listFrame,tag_pyclass = None)
|
||||
self.addLighZone.pack(side=Tkinter.LEFT)
|
||||
insideFrame = self.addLighZone.interior()
|
||||
self.lightsButton = Menubutton(insideFrame, text = 'Add light',borderwidth = 3,
|
||||
activebackground = '#909090')
|
||||
lightsMenu = Menu(self.lightsButton)
|
||||
lightsMenu.add_command(label = 'Add Ambient Light',
|
||||
command = self.addAmbient)
|
||||
lightsMenu.add_command(label = 'Add Directional Light',
|
||||
command = self.addDirectional)
|
||||
lightsMenu.add_command(label = 'Add Point Light',
|
||||
command = self.addPoint)
|
||||
lightsMenu.add_command(label = 'Add Spotlight',
|
||||
command = self.addSpot)
|
||||
|
||||
self.lightsButton.pack(expand=0)
|
||||
self.lightsButton['menu'] = lightsMenu
|
||||
|
||||
self.deleteButton = self.createcomponent(
|
||||
'delete Light', (), None,
|
||||
Button, (listFrame,),
|
||||
text = ' Delete ',
|
||||
command = self.deleteLight)
|
||||
self.deleteButton.pack(side=Tkinter.LEFT)
|
||||
|
||||
self.lightColor = seColorEntry(
|
||||
mainFrame, text = 'Light Color', value=self.lightColor)
|
||||
self.lightColor['command'] = self.setLightingColorVec
|
||||
self.lightColor['resetValue'] = [0.3*255,0.3*255,0.3*255,0]
|
||||
self.lightColor.pack(fill=Tkinter.X,expand=0)
|
||||
self.bind(self.lightColor, 'Set light color')
|
||||
|
||||
# Notebook pages for light specific controls
|
||||
self.lightNotebook = Pmw.NoteBook(mainFrame, tabpos = None,
|
||||
borderwidth = 0)
|
||||
ambientPage = self.lightNotebook.add('Ambient')
|
||||
directionalPage = self.lightNotebook.add('Directional')
|
||||
pointPage = self.lightNotebook.add('Point')
|
||||
spotPage = self.lightNotebook.add('Spot')
|
||||
# Put this here so it isn't called right away
|
||||
self.lightNotebook['raisecommand'] = self.updateLightInfo
|
||||
|
||||
# Directional light controls
|
||||
self.dSpecularColor = seColorEntry(
|
||||
directionalPage, text = 'Specular Color')
|
||||
self.dSpecularColor['command'] = self.setSpecularColor
|
||||
self.dSpecularColor.pack(fill = Tkinter.X, expand = 0)
|
||||
self.bind(self.dSpecularColor,
|
||||
'Set directional light specular color')
|
||||
self.dPosition = Vector3Entry(
|
||||
directionalPage, text = 'Position')
|
||||
self.dPosition['command'] = self.setPosition
|
||||
self.dPosition['resetValue'] = [0,0,0,0]
|
||||
self.dPosition.pack(fill = Tkinter.X, expand = 0)
|
||||
self.bind(self.dPosition, 'Set directional light position')
|
||||
self.dOrientation = Vector3Entry(
|
||||
directionalPage, text = 'Orientation')
|
||||
self.dOrientation['command'] = self.setOrientation
|
||||
self.dOrientation['resetValue'] = [0,0,0,0]
|
||||
self.dOrientation.pack(fill = Tkinter.X, expand = 0)
|
||||
self.bind(self.dOrientation, 'Set directional light orientation')
|
||||
|
||||
# Point light controls
|
||||
self.pSpecularColor = seColorEntry(
|
||||
pointPage, text = 'Specular Color')
|
||||
self.pSpecularColor['command'] = self.setSpecularColor
|
||||
self.pSpecularColor.pack(fill = Tkinter.X, expand = 0)
|
||||
self.bind(self.pSpecularColor,
|
||||
'Set point light specular color')
|
||||
|
||||
self.pPosition = Vector3Entry(
|
||||
pointPage, text = 'Position')
|
||||
self.pPosition['command'] = self.setPosition
|
||||
self.pPosition['resetValue'] = [0,0,0,0]
|
||||
self.pPosition.pack(fill = Tkinter.X, expand = 0)
|
||||
self.bind(self.pPosition, 'Set point light position')
|
||||
|
||||
self.pConstantAttenuation = Slider(
|
||||
pointPage,
|
||||
text = 'Constant Attenuation',
|
||||
max = 1.0,
|
||||
resolution = 0.01,
|
||||
value = 1.0)
|
||||
self.pConstantAttenuation['command'] = self.setConstantAttenuation
|
||||
self.pConstantAttenuation.pack(fill = Tkinter.X, expand = 0)
|
||||
self.bind(self.pConstantAttenuation,
|
||||
'Set point light constant attenuation')
|
||||
|
||||
self.pLinearAttenuation = Slider(
|
||||
pointPage,
|
||||
text = 'Linear Attenuation',
|
||||
max = 1.0,
|
||||
resolution = 0.01,
|
||||
value = 0.0)
|
||||
self.pLinearAttenuation['command'] = self.setLinearAttenuation
|
||||
self.pLinearAttenuation.pack(fill = Tkinter.X, expand = 0)
|
||||
self.bind(self.pLinearAttenuation,
|
||||
'Set point light linear attenuation')
|
||||
|
||||
self.pQuadraticAttenuation = Slider(
|
||||
pointPage,
|
||||
text = 'Quadratic Attenuation',
|
||||
max = 1.0,
|
||||
resolution = 0.01,
|
||||
value = 0.0)
|
||||
self.pQuadraticAttenuation['command'] = self.setQuadraticAttenuation
|
||||
self.pQuadraticAttenuation.pack(fill = Tkinter.X, expand = 0)
|
||||
self.bind(self.pQuadraticAttenuation,
|
||||
'Set point light quadratic attenuation')
|
||||
|
||||
# Spot light controls
|
||||
self.sSpecularColor = seColorEntry(
|
||||
spotPage, text = 'Specular Color')
|
||||
self.sSpecularColor['command'] = self.setSpecularColor
|
||||
self.sSpecularColor.pack(fill = Tkinter.X, expand = 0)
|
||||
self.bind(self.sSpecularColor,
|
||||
'Set spot light specular color')
|
||||
|
||||
self.sConstantAttenuation = Slider(
|
||||
spotPage,
|
||||
text = 'Constant Attenuation',
|
||||
max = 1.0,
|
||||
resolution = 0.01,
|
||||
value = 1.0)
|
||||
self.sConstantAttenuation['command'] = self.setConstantAttenuation
|
||||
self.sConstantAttenuation.pack(fill = Tkinter.X, expand = 0)
|
||||
self.bind(self.sConstantAttenuation,
|
||||
'Set spot light constant attenuation')
|
||||
|
||||
self.sLinearAttenuation = Slider(
|
||||
spotPage,
|
||||
text = 'Linear Attenuation',
|
||||
max = 1.0,
|
||||
resolution = 0.01,
|
||||
value = 0.0)
|
||||
self.sLinearAttenuation['command'] = self.setLinearAttenuation
|
||||
self.sLinearAttenuation.pack(fill = Tkinter.X, expand = 0)
|
||||
self.bind(self.sLinearAttenuation,
|
||||
'Set spot light linear attenuation')
|
||||
|
||||
self.sQuadraticAttenuation = Slider(
|
||||
spotPage,
|
||||
text = 'Quadratic Attenuation',
|
||||
max = 1.0,
|
||||
resolution = 0.01,
|
||||
value = 0.0)
|
||||
self.sQuadraticAttenuation['command'] = self.setQuadraticAttenuation
|
||||
self.sQuadraticAttenuation.pack(fill = Tkinter.X, expand = 0)
|
||||
self.bind(self.sQuadraticAttenuation,
|
||||
'Set spot light quadratic attenuation')
|
||||
|
||||
self.sExponent = Slider(
|
||||
spotPage,
|
||||
text = 'Exponent',
|
||||
max = 1.0,
|
||||
resolution = 0.01,
|
||||
value = 0.0)
|
||||
self.sExponent['command'] = self.setExponent
|
||||
self.sExponent.pack(fill = Tkinter.X, expand = 0)
|
||||
self.bind(self.sExponent,
|
||||
'Set spot light exponent')
|
||||
|
||||
# MRM: Add frustum controls
|
||||
|
||||
self.lightNotebook.setnaturalsize()
|
||||
self.lightNotebook.pack(expand = 1, fill = Tkinter.BOTH)
|
||||
|
||||
mainFrame.pack(expand=1, fill = Tkinter.BOTH)
|
||||
|
||||
def onDestroy(self, event):
|
||||
messenger.send('LP_close')
|
||||
'''
|
||||
If you have open any thing, please rewrite here!
|
||||
'''
|
||||
pass
|
||||
|
||||
def renameLight(self):
|
||||
#################################################################
|
||||
# renameLight(self)
|
||||
# Call Back function
|
||||
# This function will be called when user push
|
||||
# the "Rename" button on the panel.
|
||||
#
|
||||
# Then, this function will collect data and send out them with a message
|
||||
# "LP_rename"
|
||||
# Which will be caught by sceneEditor and pass to dataHolder to
|
||||
# complete the renaming.
|
||||
#
|
||||
#################################################################
|
||||
oName = self.currentLight
|
||||
nName = self.lightEntry.get()
|
||||
messenger.send('LP_rename',[oName,nName])
|
||||
return
|
||||
|
||||
def deleteLight(self):
|
||||
#################################################################
|
||||
# deleteLight(self)
|
||||
# Call Back Function.
|
||||
# This function will be called when user click on
|
||||
# the "Delete" button on the panel.
|
||||
#
|
||||
# Then, this function will send out a message with current seleted light
|
||||
# "LP_removeLight"
|
||||
# Which will be caught by sceneEditor and pass to dataHolder to
|
||||
# complete the delete process.
|
||||
#
|
||||
#################################################################
|
||||
messenger.send('LP_removeLight',[self.currentLight])
|
||||
return
|
||||
|
||||
def updateList(self, list, node=None):
|
||||
#################################################################
|
||||
# updataList(self, list, node = None)
|
||||
# This function will take a list object which contains names of lights in the scene.
|
||||
# Also, if user has put node as a parameter,
|
||||
# this function will automatically select that node as the current working target.
|
||||
#################################################################
|
||||
self.lightList = list
|
||||
self.lightEntry.setlist(list)
|
||||
if node!=None:
|
||||
self.lightEntry.selectitem(index=node.getName(), setentry=True )
|
||||
self.updateDisplay(node)
|
||||
elif len(list)>0:
|
||||
self.lightEntry.selectitem(index=0, setentry=True )
|
||||
self.selectLight(list[0])
|
||||
else:
|
||||
self.lightEntry.clear()
|
||||
return
|
||||
|
||||
def selectLight(self, lightName):
|
||||
#################################################################
|
||||
# selectLight(self, lightName)
|
||||
# This function will be called each time when
|
||||
# user select a light from the list on the panel.
|
||||
# Then, this function will send out the message,
|
||||
# 'LP_selectLight' to sceneEditorand get the current light information from dataHolder.
|
||||
#################################################################
|
||||
if lightName in self.lightList:
|
||||
messenger.send('LP_selectLight',[lightName])
|
||||
return
|
||||
|
||||
def updateDisplay(self, lightNode):
|
||||
#################################################################
|
||||
# updateDisplay(self, lightNode)
|
||||
# This function will update the information showing on the panel.
|
||||
# For example, give a lightNode which is a Point Light.
|
||||
# This function will switch the page to specify the type.
|
||||
# Also, new node is the same type with the previous one,
|
||||
# then this is function won't do the page switching,
|
||||
# but will call other function to refresh the data to target node.
|
||||
#################################################################
|
||||
self.currentLight = lightNode
|
||||
if self.currentLight != None:
|
||||
color = lightNode.getLightColor()
|
||||
self.lightColor.set([255*color.getX(),255*color.getY(),255*color.getZ()])
|
||||
oldType = self.type
|
||||
self.type = lightNode.getType()
|
||||
else:
|
||||
self.lightColor.set([255*0.3,255*0.3,255*0.3])
|
||||
oldType = self.type
|
||||
self.type = 'ambient'
|
||||
|
||||
if self.type=='ambient':
|
||||
self.lightNotebook.selectpage('Ambient')
|
||||
elif self.type =='directional':
|
||||
self.lightNotebook.selectpage('Directional')
|
||||
elif self.type =='point':
|
||||
self.lightNotebook.selectpage('Point')
|
||||
elif self.type =='spot':
|
||||
self.lightNotebook.selectpage('Spot')
|
||||
if oldType == self.type:
|
||||
# The same type with previous one, call updateLightInfo to refresh the values.
|
||||
self.updateLightInfo()
|
||||
return
|
||||
|
||||
def updateLightInfo(self, page=None):
|
||||
#################################################################
|
||||
# updateLightInfo(self, page=None)
|
||||
# This function will refresh the data we user have done any selection.
|
||||
#################################################################
|
||||
if self.currentLight != None:
|
||||
light = self.currentLight.getLight()
|
||||
if self.type != 'ambient':
|
||||
specColor = light.getSpecularColor()
|
||||
if self.type =='directional':
|
||||
point = self.currentLight.getPosition()
|
||||
dir = self.currentLight.getOrientation()
|
||||
self.dSpecularColor.set([specColor.getX()*255,specColor.getY()*255,specColor.getZ()*255])
|
||||
self.dPosition.set([point.getX(),point.getY(),point.getZ()])
|
||||
self.dOrientation.set([dir.getX(),dir.getY(),dir.getZ()])
|
||||
elif self.type =='point':
|
||||
point = self.currentLight.getPosition()
|
||||
attenuation = light.getAttenuation()
|
||||
self.pSpecularColor.set([specColor.getX()*255,specColor.getY()*255,specColor.getZ()*255])
|
||||
self.pPosition.set([point.getX(),point.getY(),point.getZ()])
|
||||
self.pConstantAttenuation.set(attenuation.getX())
|
||||
self.pLinearAttenuation.set(attenuation.getY())
|
||||
self.pQuadraticAttenuation.set(attenuation.getZ())
|
||||
elif self.type =='spot':
|
||||
attenuation = light.getAttenuation()
|
||||
expo = light.getExponent()
|
||||
self.sSpecularColor.set([specColor.getX()*255,specColor.getY()*255,specColor.getZ()*255])
|
||||
self.sConstantAttenuation.set(attenuation.getX())
|
||||
self.sLinearAttenuation.set(attenuation.getY())
|
||||
self.sQuadraticAttenuation.set(attenuation.getZ())
|
||||
self.sExponent.set(expo)
|
||||
return
|
||||
|
||||
def addAmbient(self):
|
||||
#################################################################
|
||||
# addAmbient(self)
|
||||
# This function will send out a message to
|
||||
# ask dataHolder to create a default ambient light
|
||||
#################################################################
|
||||
messenger.send('LP_addLight',['ambient'])
|
||||
return
|
||||
|
||||
def addDirectional(self):
|
||||
#################################################################
|
||||
# addDirectional(self)
|
||||
# This function will send out a message to
|
||||
# sk dataHolder to create a default Directional light
|
||||
#################################################################
|
||||
messenger.send('LP_addLight',['directional'])
|
||||
return
|
||||
|
||||
def addPoint(self):
|
||||
#################################################################
|
||||
# addPoint(self)
|
||||
# This function will send out a message to
|
||||
# ask dataHolder to create a default Point light
|
||||
#################################################################
|
||||
messenger.send('LP_addLight',['point'])
|
||||
return
|
||||
|
||||
def addSpot(self):
|
||||
#################################################################
|
||||
# addSpot(self)
|
||||
# This function will send out a message to
|
||||
# ask dataHolder to create a default Spot light
|
||||
#################################################################
|
||||
messenger.send('LP_addLight',['spot'])
|
||||
return
|
||||
|
||||
def setLightingColorVec(self,color):
|
||||
#################################################################
|
||||
# setLightingColorVec(self,color)
|
||||
# Call Back function. This will be called
|
||||
# when user try to change the color of light.
|
||||
#################################################################
|
||||
if self.currentLight==None:
|
||||
return
|
||||
self.currentLight.setColor(VBase4((color[0]/255),(color[1]/255),(color[2]/255),1))
|
||||
return
|
||||
|
||||
def setSpecularColor(self,color):
|
||||
#################################################################
|
||||
# setSpecularColor(self,color)
|
||||
# Call Back function. This will be called
|
||||
# when user try to change the Specular color of light.
|
||||
#################################################################
|
||||
if self.currentLight==None:
|
||||
return
|
||||
self.currentLight.setSpecColor(VBase4((color[0]/255),(color[1]/255),(color[2]/255),1))
|
||||
return
|
||||
|
||||
def setPosition(self,position):
|
||||
#################################################################
|
||||
# setPosition(self,position)
|
||||
# Call Back function. This will be called
|
||||
# when user try to change the position of light.
|
||||
#################################################################
|
||||
if self.currentLight==None:
|
||||
return
|
||||
self.currentLight.setPosition(Point3(position[0],position[1],position[2]))
|
||||
return
|
||||
|
||||
def setOrientation(self, orient):
|
||||
#################################################################
|
||||
# setOrientation(self, orient)
|
||||
# Call Back function. This will be called
|
||||
# when user try to change the orientation of light.
|
||||
#################################################################
|
||||
if self.currentLight==None:
|
||||
return
|
||||
self.currentLight.setOrientation(Vec3(orient[0],orient[1],orient[2]))
|
||||
return
|
||||
|
||||
def setConstantAttenuation(self, value):
|
||||
#################################################################
|
||||
# setConstantAttenuation(self, value)
|
||||
# Call Back function. This will be called
|
||||
# when user try to change the Constant Attenuation of light.
|
||||
#################################################################
|
||||
self.currentLight.setConstantAttenuation(value)
|
||||
return
|
||||
|
||||
def setLinearAttenuation(self, value):
|
||||
#################################################################
|
||||
# setLinearAttenuation(self, value)
|
||||
# Call Back function. This will be called
|
||||
# when user try to change the Linear Attenuation of light.
|
||||
#################################################################
|
||||
self.currentLight.setLinearAttenuation(value)
|
||||
return
|
||||
|
||||
def setQuadraticAttenuation(self, value):
|
||||
#################################################################
|
||||
# setQuadraticAttenuation(self, value)
|
||||
# Call Back function. This will be called
|
||||
# when user try to change the Quadratic Attenuation of light.
|
||||
#################################################################
|
||||
self.currentLight.setQuadraticAttenuation(value)
|
||||
return
|
||||
|
||||
def setExponent(self, value):
|
||||
#################################################################
|
||||
# setExponent(self, value)
|
||||
# Call Back function. This will be called
|
||||
# when user try to change Exponent value of light.
|
||||
#################################################################
|
||||
self.currentLight.setExponent(value)
|
||||
return
|
1456
build/nirai/panda3d/contrib/src/sceneeditor/propertyWindow.py
Normal file
1456
build/nirai/panda3d/contrib/src/sceneeditor/propertyWindow.py
Normal file
File diff suppressed because it is too large
Load diff
676
build/nirai/panda3d/contrib/src/sceneeditor/quad.py
Normal file
676
build/nirai/panda3d/contrib/src/sceneeditor/quad.py
Normal file
|
@ -0,0 +1,676 @@
|
|||
#########################################################################################################################################
|
||||
# This file implements a Quad View for the level editor
|
||||
# This feature is not yet enabled in the level editor because picking objects in quad view doesnt work
|
||||
# I have tried to send the picking function in seSelection.py the correct camera and mouse coordinates but something seems to be wron
|
||||
# There are two classes in this file..the QuadView and the viewPort...there are four instances of viewport, one for each view in QuadView
|
||||
#########################################################################################################################################
|
||||
|
||||
|
||||
from direct.showbase.ShowBaseGlobal import *
|
||||
from direct.interval.IntervalGlobal import *
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from pandac.PandaModules import *
|
||||
import math
|
||||
#Manakel 2/12/2005: replace from pandac import by from pandac.PandaModules import
|
||||
from pandac.PandaModules import MouseWatcher
|
||||
|
||||
|
||||
class ViewPort:
|
||||
#########################################################################################################################################
|
||||
# The ViewPort class has the camera and associated display region set up for actually rendering the four sub-views
|
||||
# The constructor needs the bounds, window layer, camera, color, projection type, name and scene for the view
|
||||
#########################################################################################################################################
|
||||
|
||||
def __init__(self,X1,X2,Y1,Y2,layer,cam,background=Vec4(0.3,0.3,0.3,1),projection="perspective",type="top",scene=render):
|
||||
self.VPType=type
|
||||
self.VP_X1=X1
|
||||
self.VP_Y1=Y1
|
||||
self.VP_X2=X2
|
||||
self.VP_Y2=Y2
|
||||
self.VP_width=self.VP_X2 - self.VP_X1
|
||||
self.VP_height=self.VP_Y2 - self.VP_Y1
|
||||
|
||||
self.the_viewport=layer.makeDisplayRegion(self.VP_X1, self.VP_X2,self.VP_Y1, self.VP_Y2)
|
||||
self.the_viewport.setCamera(cam)
|
||||
self.the_viewport.setClearDepthActive(1)
|
||||
self.the_viewport.setClearColorActive(1)
|
||||
self.the_viewport.setClearColor(background)
|
||||
self.cam=cam
|
||||
|
||||
|
||||
# Set up the cameras to look in the right place.
|
||||
if(type=="top"):
|
||||
self.cam.setP(-90)
|
||||
self.cam.setZ(-40)
|
||||
elif(type=="left"):
|
||||
self.cam.setH(-90)
|
||||
self.cam.setX(10)
|
||||
elif(type=="front"):
|
||||
self.cam.setY(-10)
|
||||
elif(type=="perspective"):
|
||||
cam.setY(-100)
|
||||
#cam.setX(10)
|
||||
#cam.setZ(-10)
|
||||
#cam.setH(45)
|
||||
#cam.setP(-45)
|
||||
#print "aa"
|
||||
|
||||
|
||||
if(projection=="ortho"):
|
||||
self.lens=OrthographicLens()
|
||||
self.lens.setAspectRatio((self.VP_X2-self.VP_X1)/(self.VP_Y2-self.VP_Y1))
|
||||
self.lens.setFilmSize(self.VP_width*200,self.VP_height*200)
|
||||
#lens.setFilmOffset((self.VP_X2 + self.VP_X1) * 0.5, (self.VP_Y2 + self.VP_Y1) * 0.5)
|
||||
self.lens.setNearFar(-1000, 1000)
|
||||
self.cam.node().setLens(self.lens)
|
||||
self.cam.node().setScene(scene)
|
||||
elif(projection=="perspective"):
|
||||
self.lens=base.cam.node().getLens()
|
||||
self.lens.setAspectRatio((self.VP_X2-self.VP_X1)/(self.VP_Y2-self.VP_Y1))
|
||||
self.cam.node().setLens(self.lens)
|
||||
self.cam.node().setScene(scene)
|
||||
|
||||
self.the_viewport.setCamera(self.cam)
|
||||
|
||||
def resizeX(self,width_increment):
|
||||
if(self.VPType=="top" or self.VPType=="left"):
|
||||
self.the_viewport.setDimensions(self.VP_X1,self.VP_X2+width_increment,self.VP_Y1,self.VP_Y2)
|
||||
elif(self.VPType=="perspective" or self.VPType=="front"):
|
||||
self.the_viewport.setDimensions(self.VP_X1+width_increment,self.VP_X2,self.VP_Y1,self.VP_Y2)
|
||||
|
||||
def resizeY(self,height_increment,direction):
|
||||
if(self.VPType=="left" or self.type=="perspective"):
|
||||
self.the_viewport.setDimensions(self.VP_X1,self.VP_X2,self.VP_Y1,self.VP_Y2+height_increment)
|
||||
else:
|
||||
self.the_viewport.setDimensions(self.VP_X1,self.VP_X2,self.VP_Y1+height_increment,self.VP_Y2)
|
||||
|
||||
def AdjustAspect(self,x,y):
|
||||
if (y==0):
|
||||
y=1
|
||||
self.lens.setAspectRatio(x/y)
|
||||
self.cam.node().setLens(self.lens)
|
||||
|
||||
def resize(self,x,y):
|
||||
|
||||
if(self.VPType=="left"):
|
||||
self.the_viewport.setDimensions(0,x,0,y)
|
||||
w=abs(x-self.VP_X1)
|
||||
h=abs(y-self.VP_Y1)
|
||||
if(h==0):
|
||||
h=1
|
||||
self.lens.setAspectRatio(w/h)
|
||||
self.cam.node().setLens(self.lens)
|
||||
if(self.VPType=="top"):
|
||||
self.the_viewport.setDimensions(0,x,y,1)
|
||||
w=abs(x-self.VP_X1)
|
||||
h=abs(self.VP_Y2-y)
|
||||
if(h==0):
|
||||
h=1
|
||||
self.lens.setAspectRatio(w/h)
|
||||
self.cam.node().setLens(self.lens)
|
||||
if(self.VPType=="front"):
|
||||
self.the_viewport.setDimensions(x,1,y,1)
|
||||
w=abs(self.VP_X2-x)
|
||||
h=abs(self.VP_Y2-y)
|
||||
if(h==0):
|
||||
h=1
|
||||
self.lens.setAspectRatio(w/h)
|
||||
self.cam.node().setLens(self.lens)
|
||||
if(self.VPType=="perspective"):
|
||||
self.the_viewport.setDimensions(x,1,0,y)
|
||||
w=abs(self.VP_X2-x)
|
||||
h=abs(y-self.VP_Y1)
|
||||
if(h==0):
|
||||
h=1
|
||||
self.lens.setAspectRatio(w/h)
|
||||
self.cam.node().setLens(self.lens)
|
||||
|
||||
def setScene(self,scene):
|
||||
self.cam.node().setScene(scene)
|
||||
|
||||
def setDR(self,mouseWatcher):
|
||||
#mouseWatcher.setDisplayRegion(self.the_viewport)
|
||||
pass
|
||||
|
||||
def setCam(self):
|
||||
#base.cam=self.cam
|
||||
#base.cam.node().setLens(self.cam.node().getLens())
|
||||
base.camNode=self.cam.node()
|
||||
#base.camNode.setLens(self.cam.node().getLens())
|
||||
#base.camLens=self.cam.node().getLens()
|
||||
|
||||
def getCam(self):
|
||||
return self.cam
|
||||
|
||||
|
||||
class QuadView(DirectObject):
|
||||
#########################################################################################################################################
|
||||
# This class sets up four cameras for the scene (ideally we want four instances of render too)
|
||||
# and then instatiates a ViewPort class for each of them
|
||||
#
|
||||
#########################################################################################################################################
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.PTracker=1
|
||||
self.ControlPressed=0
|
||||
self.AltPressed=0
|
||||
self.PanConstantX=50
|
||||
self.PanConstantY=50
|
||||
self.ZoomConstant=1
|
||||
self.FrontWidth=100
|
||||
self.FrontHeight=100
|
||||
self.TopWidth=100
|
||||
self.TopHeight=100
|
||||
self.LeftWidth=100
|
||||
self.LeftHeight=100
|
||||
|
||||
self.MouseButton=0
|
||||
self.CurrentQuad=4
|
||||
self.HorizontalAxis=0.0
|
||||
self.VerticalAxis=0.0
|
||||
#base.disableMouse()
|
||||
self.MouseDragging=0
|
||||
self.currX= 0
|
||||
self.oldX=self.currX
|
||||
self.currY= 0
|
||||
self.oldY=self.currY
|
||||
|
||||
self.FrontTexture=1
|
||||
self.LeftTexture=1
|
||||
self.PerspectiveTexture=1
|
||||
self.TopTexture=1
|
||||
|
||||
self.FrontWire=0
|
||||
self.LeftWire=0
|
||||
self.PerspectiveWire=0
|
||||
self.TopWire=0
|
||||
|
||||
# Keep track of the currently selected window... values are 1-4 for four quadrants of a standard
|
||||
# Cartesian coordinate system
|
||||
|
||||
# These are the orthographic cameras
|
||||
# They will be restricted to panning and zooming i.e. no rotation
|
||||
# Top could be flipped to back, left to right and front to back
|
||||
self.topCam= render.attachNewNode(Camera('topCam'))
|
||||
self.frontCam = render.attachNewNode(Camera('frontCam'))
|
||||
self.leftCam= render.attachNewNode(Camera('leftCam'))
|
||||
|
||||
# This camera will have a trackball control since its perspective
|
||||
self.perspectiveCam = render.attachNewNode(Camera('perspectiveCam'))
|
||||
|
||||
#self.toplens=OrthographicLens()
|
||||
#self.leftLens=OrthographicLens()
|
||||
#self.frontLens=OrthographicLens()
|
||||
#self.perspectiveLens=base.cam.node().getLens()
|
||||
|
||||
# For now all lenses are same as that of base.cam
|
||||
#self.topCamLens=OrthographicLens()
|
||||
#self.frontCamLens= base.cam.node().getLens()
|
||||
#self.leftCamLens= base.cam.node().getLens()
|
||||
#self.perspectiveCamLens= base.cam.node().getLens()
|
||||
|
||||
# Manipulate lenses here if need be
|
||||
#self.topCamLens.setFilmSize(250)
|
||||
|
||||
# Set the Lenses
|
||||
#self.topCam.node().setLens(self.topCamLens)
|
||||
#self.frontCam.node().setLens(self.frontCamLens)
|
||||
#self.leftCam.node().setLens(self.leftCamLens)
|
||||
#self.perspectiveCam.node().setLens(self.perspectiveCamLens)
|
||||
|
||||
#self.badwiz = loader.loadModel('badwizard1')
|
||||
#self.badwiz.reparentTo(render)
|
||||
|
||||
# Create four separate display regions for the quad view.
|
||||
# These will overlap the main display region
|
||||
# To stack these overlapping DisplayRegions, we need a new layer. If
|
||||
# they didn't overlap, we could put them in the same layer.
|
||||
|
||||
self.newLayer = base.win.getChannel(0).makeLayer()
|
||||
|
||||
self.PerspectiveScene=NodePath('PerspectiveScene')
|
||||
self.FrontScene=NodePath('FrontScene')
|
||||
self.TopScene=NodePath('TopScene')
|
||||
self.LeftScene=NodePath('LeftScene')
|
||||
self.SceneParent=NodePath('SceneParent')
|
||||
|
||||
#self.PerspectiveScene=render.copyTo(self.SceneParent)
|
||||
#self.FrontScene=render.copyTo(self.SceneParent)
|
||||
#self.TopScene=render.copyTo(self.SceneParent)
|
||||
#self.LeftScene=render.copyTo(self.SceneParent)
|
||||
|
||||
self.PerspectiveScene=render
|
||||
self.FrontScene=render
|
||||
self.TopScene=render
|
||||
self.LeftScene=render
|
||||
|
||||
#self.PerspectiveScene.reparentTo(self.SceneParent)
|
||||
#self.FrontScene.reparentTo(self.SceneParent)
|
||||
#self.TopScene.reparentTo(self.SceneParent)
|
||||
#self.LeftScene.reparentTo(self.SceneParent)
|
||||
|
||||
self.Perspective=ViewPort(0.5,1.0,0.0,0.5,self.newLayer,self.perspectiveCam,Vec4(0.75,0.75,0.75,1),"perspective","perspective",self.PerspectiveScene)
|
||||
self.Top=ViewPort(0.0,0.5,0.5,1.0,self.newLayer,self.topCam,Vec4(0.80,0.80,0.80,1),"ortho","top",self.TopScene)
|
||||
self.Left=ViewPort(0.0,0.5,0.0,0.5,self.newLayer,self.leftCam,Vec4(0.85,0.85,0.85,1),"ortho","left",self.LeftScene)
|
||||
self.Front=ViewPort(0.5,1.0,0.5,1.0,self.newLayer,self.frontCam,Vec4(0.85,0.85,0.85,1),"ortho","front",self.FrontScene)
|
||||
#self.Perspective=None
|
||||
#self.Top=None
|
||||
#self.Front=None
|
||||
#self.Left=None
|
||||
|
||||
#self.raycaster = RayCaster( camera )
|
||||
#self.lastPickPoint = None
|
||||
|
||||
#base.useTrackball()
|
||||
|
||||
#self.dataRoot = NodePath('dataRoot')
|
||||
# Cache the node so we do not ask for it every frame
|
||||
#self.dataRootNode = self.dataRoot.node()
|
||||
#self.dataUnused = NodePath('dataUnused')
|
||||
#self.mak=None
|
||||
#self.mak = self.dataRoot.attachNewNode(MouseAndKeyboard(base.win, 0, 'mak'))
|
||||
#self.mak.node().setSource(base.win, 0)
|
||||
self.mouseWatcherNode = MouseWatcher('mouseWatcher')
|
||||
|
||||
self.mouseWatcher = base.mak.attachNewNode(self.mouseWatcherNode)
|
||||
#self.Perspective.setDR(self.mouseWatcherNode)
|
||||
|
||||
self.buttonThrower = self.mouseWatcher.attachNewNode(ButtonThrower('buttons'))
|
||||
|
||||
|
||||
#ddr=DisplayRegionContext(self.Perspective.getCam())
|
||||
#base.setMouseOnNode(self.smiley.node()) # Let Mouse Control Perspective View for now
|
||||
#base.enableSoftwareMousePointer()
|
||||
|
||||
# Message Handlers
|
||||
self.accept("a",self.setLeft)
|
||||
self.accept("q",self.setTop)
|
||||
self.accept("w",self.setFront)
|
||||
self.accept("s",self.setPerspective)
|
||||
self.accept("mouse1",self.MouseTell,[1])
|
||||
self.accept("mouse2",self.MouseTell,[2])
|
||||
self.accept("mouse3",self.MouseTell,[3])
|
||||
self.accept("mouse1-up",self.MouseTellUp,[4])
|
||||
self.accept("mouse2-up",self.MouseTellUp,[5])
|
||||
self.accept("mouse3-up",self.MouseTellUp,[6])
|
||||
self.accept("mouse2-scroll",self.resizedr)
|
||||
self.accept("r",self.resizedr)
|
||||
self.accept("alt",self.AltHandler)
|
||||
self.accept("alt-up",self.AltUpHandler)
|
||||
self.accept("alt-mouse1",self.AltDown)
|
||||
self.accept("alt-mouse1-up",self.AltUp)
|
||||
self.accept("control-mouse1",self.CtlDown)
|
||||
self.accept("control-mouse1-up",self.CtlUp)
|
||||
|
||||
# Methods
|
||||
|
||||
#def setLastPickPoint( self ):
|
||||
# mouseX, mouseY = self.mouseWatcherNode.getMouseX(), self.mouseWatcherNode.getMouseY()
|
||||
# self.lastPickPoint = self.raycaster.pick( mouseX, mouseY )
|
||||
# print self.lastPickPoint
|
||||
|
||||
def AltDown(self):
|
||||
self.AltPressed=1
|
||||
|
||||
|
||||
def AltUp(self):
|
||||
self.AltPressed=0
|
||||
|
||||
|
||||
def CtlDown(self):
|
||||
self.ControlPressed=1
|
||||
|
||||
|
||||
def CtlUp(self):
|
||||
self.ControlPressed=0
|
||||
|
||||
|
||||
def ToggleWire(self):
|
||||
if (self.CurrentQuad==1): # Front View
|
||||
if(self.FrontWire): # Wireframe is On so turn it off
|
||||
self.FrontScene.setRenderModeWireframe(100)
|
||||
self.FrontScene.setTwoSided(1)
|
||||
self.FrontScene.setTextureOff(100)
|
||||
self.FrontWire=0
|
||||
else:
|
||||
self.FrontScene.clearRenderMode()
|
||||
#self.FrontScene.setTwoSided(not self.backfaceCullingEnabled)
|
||||
if(self.FrontTexture):
|
||||
self.FrontScene.clearTexture()
|
||||
self.FrontWire=1
|
||||
elif (self.CurrentQuad==2): # Front View
|
||||
if(self.TopWire): # Wireframe is On so turn it off
|
||||
self.TopScene.setRenderModeWireframe(100)
|
||||
self.TopScene.setTwoSided(1)
|
||||
self.TopScene.setTextureOff(100)
|
||||
self.TopWire=0
|
||||
else:
|
||||
self.TopScene.clearRenderMode()
|
||||
#self.TopScene.setTwoSided(not self.backfaceCullingEnabled)
|
||||
if(self.TopTexture):
|
||||
self.TopScene.clearTexture()
|
||||
self.TopWire=1
|
||||
elif (self.CurrentQuad==3): # Front View
|
||||
if(self.LeftWire): # Wireframe is On so turn it off
|
||||
self.LeftScene.setRenderModeWireframe(100)
|
||||
self.LeftScene.setTwoSided(1)
|
||||
self.LeftScene.setTextureOff(100)
|
||||
self.LeftWire=0
|
||||
else:
|
||||
self.LeftScene.clearRenderMode()
|
||||
#self.LeftScene.setTwoSided(not self.backfaceCullingEnabled)
|
||||
if(self.LeftTexture):
|
||||
self.LeftScene.clearTexture()
|
||||
self.LeftWire=1
|
||||
elif (self.CurrentQuad==4): # Front View
|
||||
if(self.PerspectiveWire): # Wireframe is On so turn it off
|
||||
self.PerspectiveScene.setRenderModeWireframe(100)
|
||||
self.PerspectiveScene.setTwoSided(1)
|
||||
self.PerspectiveScene.setTextureOff(100)
|
||||
self.PerspectiveWire=0
|
||||
else:
|
||||
self.PerspectiveScene.clearRenderMode()
|
||||
#self.PerspectiveScene.setTwoSided(not self.backfaceCullingEnabled)
|
||||
if(self.PerspectiveTexture):
|
||||
self.PerspectiveScene.clearTexture()
|
||||
self.PerspectiveWire=1
|
||||
|
||||
|
||||
def ToggleTexture(self):
|
||||
if (self.CurrentQuad==1): # Front View
|
||||
if(self.FrontTexture): # Texture is on so turn it off
|
||||
self.FrontScene.setTextureOff(100)
|
||||
self.FrontTexture=0
|
||||
else:
|
||||
self.FrontScene.clearTexture()
|
||||
self.FrontTexture=1
|
||||
elif (self.CurrentQuad==2): # Top View
|
||||
if(self.TopTexture): # Texture is on so turn it off
|
||||
self.TopScene.setTextureOff(100)
|
||||
self.TopTexture=0
|
||||
else:
|
||||
self.TopScene.clearTexture()
|
||||
self.TopTexture=1
|
||||
elif (self.CurrentQuad==3): # Left View
|
||||
if(self.LeftTexture): # Texture is on so turn it off
|
||||
self.LeftScene.setTextureOff(100)
|
||||
self.LeftTexture=0
|
||||
else:
|
||||
self.LeftScene.clearTexture()
|
||||
self.LeftTexture=1
|
||||
elif (self.CurrentQuad==4): # Perspective View
|
||||
if(self.PerspectiveTexture): # Texture is on so turn it off
|
||||
self.PerspectiveScene.setTextureOff(100)
|
||||
self.PerspectiveTexture=0
|
||||
else:
|
||||
self.PerspectiveScene.clearTexture()
|
||||
self.PerspectiveTexture=1
|
||||
|
||||
|
||||
|
||||
def reparenter(self):
|
||||
#self.FrontScene.reparentTo(render)
|
||||
#self.Front.setScene(render)
|
||||
#self.Top.setScene(render)
|
||||
#self.Left.setScene(render)
|
||||
#self.Perspective.setScene(render)
|
||||
pass
|
||||
|
||||
def unparenter(self):
|
||||
#self.PerspectiveScene=render.copyTo(render)
|
||||
#self.FrontScene=render.copyTo(render)
|
||||
#self.TopScene=render.copyTo(render)
|
||||
#self.LeftScene=render.copyTo(render)
|
||||
#self.SceneParent.reparentTo(render)
|
||||
#self.PerspectiveScene.reparentTo(self.SceneParent)
|
||||
#self.FrontScene.reparentTo(self.SceneParent)
|
||||
#self.TopScene.reparentTo(self.SceneParent)
|
||||
#self.LeftScene.reparentTo(self.SceneParent)
|
||||
pass
|
||||
|
||||
def AltHandler(self):
|
||||
self.oldX=self.mouseWatcherNode.getMouseX()
|
||||
if(self.oldX<-1 or self.oldX>1):
|
||||
return
|
||||
self.oldY=self.mouseWatcherNode.getMouseY()
|
||||
if(self.oldY<-1 or self.oldY>1):
|
||||
return
|
||||
taskMgr.add(self.DragAction,'DragAction')
|
||||
|
||||
def AltUpHandler(self):
|
||||
taskMgr.remove('DragAction')
|
||||
|
||||
def gridtoggle(self):
|
||||
#grid=DirectGrid()
|
||||
#grid.enable()
|
||||
pass
|
||||
|
||||
def resizedr(self,x,y):
|
||||
#print "X: " + str(x) + " Y: " + str(y)
|
||||
x=(x+1)/2.0
|
||||
y=(y+1)/2.0
|
||||
self.Perspective.resize(x,y)
|
||||
self.Top.resize(x,y)
|
||||
self.Front.resize(x,y)
|
||||
self.Left.resize(x,y)
|
||||
|
||||
def setAppropriateViewPort(self,x,y):
|
||||
#print "SET APPROPRIATE:" + str(x) + " " + str(y)
|
||||
if(x<self.VerticalAxis):
|
||||
if(y<self.HorizontalAxis):
|
||||
self.setLeft()
|
||||
else:
|
||||
self.setTop()
|
||||
else:
|
||||
if(y<self.HorizontalAxis):
|
||||
self.setPerspective()
|
||||
else:
|
||||
self.setFront()
|
||||
|
||||
def MouseTell(self,buttonCode):
|
||||
self.MouseButton=buttonCode
|
||||
self.setAppropriateViewPort(self.mouseWatcherNode.getMouseX(),self.mouseWatcherNode.getMouseY())
|
||||
|
||||
x=base.mouseWatcherNode.getMouseX()
|
||||
y=base.mouseWatcherNode.getMouseY()
|
||||
|
||||
#Perspective and Front
|
||||
if(self.CurrentQuad==4 or self.CurrentQuad==1):
|
||||
x1=abs(x-self.VerticalAxis)
|
||||
w1=abs(1-self.VerticalAxis)
|
||||
x2=x1*2.0/w1
|
||||
ansX=-1+x2
|
||||
|
||||
|
||||
#Left and top
|
||||
if(self.CurrentQuad==2 or self.CurrentQuad==3):
|
||||
x1=abs(x-(-1.0))
|
||||
w1=abs(self.VerticalAxis-(-1.0))
|
||||
x2=x1*2.0/w1
|
||||
ansX=-1.0+x2
|
||||
|
||||
#Left and Perspective
|
||||
if(self.CurrentQuad==4 or self.CurrentQuad==3):
|
||||
y1=abs(y-(-1.0))
|
||||
h1=abs(self.HorizontalAxis-(-1.0))
|
||||
y2=y1*2.0/h1
|
||||
ansY=-1.0+y2
|
||||
|
||||
|
||||
#Front and top
|
||||
if(self.CurrentQuad==1 or self.CurrentQuad==2):
|
||||
y1=abs(y-self.HorizontalAxis)
|
||||
h1=abs(1.0-self.HorizontalAxis)
|
||||
y2=y1*2.0/h1
|
||||
ansY=-1.0+y2
|
||||
|
||||
self.xy=[ansX,ansY]
|
||||
print "Sent X:%f Sent Y:%f"%(ansX,ansY)
|
||||
#SEditor.iRay.pick(render,self.xy)
|
||||
SEditor.manipulationControl.manipulationStop(self.xy)
|
||||
#print "MouseX " + str(base.mouseWatcherNode.getMouseX()) + "MouseY " + str(base.mouseWatcherNode.getMouseY()) + "\n"
|
||||
#print "MouseX " + str(self.mouseWatcherNode.getMouseX()) + "MouseY " + str(self.mouseWatcherNode.getMouseY()) + "\n"
|
||||
|
||||
|
||||
base.mouseWatcherNode=self.mouseWatcherNode
|
||||
|
||||
self.oldX=self.mouseWatcherNode.getMouseX()
|
||||
if(self.oldX<-1 or self.oldX>1):
|
||||
return
|
||||
|
||||
self.oldY=self.mouseWatcherNode.getMouseY()
|
||||
if(self.oldY<-1 or self.oldY>1):
|
||||
return
|
||||
self.Mouse_Dragging=1
|
||||
taskMgr.add(self.DragAction,'DragAction')
|
||||
|
||||
def MouseTellUp(self,buttoncode):
|
||||
#self.MouseButton=0
|
||||
self.PanConstantX= 50
|
||||
self.PanConstantY= 50
|
||||
self.ZoomConstant=1
|
||||
taskMgr.remove('DragAction')
|
||||
self.Mouse_Draggin=0
|
||||
#print "Mouse Up"
|
||||
|
||||
|
||||
def Max_Style_Mouse_View(self,buttoncode):
|
||||
pass
|
||||
|
||||
def ChangeBaseDR(self):
|
||||
dr=base.win.getDisplayRegion(0)
|
||||
if(self.CurrentQuad==1): #Front
|
||||
dr.setDimensions(0.5,1,0.5,1)
|
||||
elif(self.CurrentQuad==2): #Top
|
||||
dr.setDimensions(0,0.5,0.5,1)
|
||||
elif(self.CurrentQuad==3): #Left
|
||||
dr.setDimensions(0,0.5,0,0.5)
|
||||
elif(self.CurrentQuad==4): #Perspective
|
||||
dr.setDimensions(0.5,1,0,0.5)
|
||||
|
||||
def setLeft(self):
|
||||
print "LEFT"
|
||||
self.CurrentQuad=3
|
||||
self.ChangeBaseDR()
|
||||
self.Left.setCam()
|
||||
#self.Left.setDR(self.mouseWatcherNode)
|
||||
|
||||
def setTop(self):
|
||||
print "TOP"
|
||||
self.CurrentQuad=2
|
||||
self.ChangeBaseDR()
|
||||
self.Top.setCam()
|
||||
#self.Top.setDR(self.mouseWatcherNode)
|
||||
|
||||
def setPerspective(self):
|
||||
print "PERSPECTIVE"
|
||||
self.CurrentQuad=4
|
||||
self.ChangeBaseDR()
|
||||
self.Perspective.setCam()
|
||||
#self.Perspective.setDR(self.mouseWatcherNode)
|
||||
|
||||
def setFront(self):
|
||||
print "FRONT"
|
||||
self.CurrentQuad=1
|
||||
self.ChangeBaseDR()
|
||||
self.Front.setCam()
|
||||
#self.Front.setDR(self.mouseWatcherNode)
|
||||
|
||||
|
||||
def DragAction(self,task):
|
||||
#if(self.MouseDragging==1):
|
||||
self.currX= self.mouseWatcherNode.getMouseX()
|
||||
if(self.currX<-1 or self.currX>1):
|
||||
return
|
||||
self.currY= self.mouseWatcherNode.getMouseY()
|
||||
if(self.currY<-1 or self.currY>1):
|
||||
return
|
||||
|
||||
|
||||
self.diffX=self.currX-self.oldX
|
||||
self.diffY=self.currY-self.oldY
|
||||
|
||||
if(self.ControlPressed): # Change Size of the ViewPorts
|
||||
#if(base.getControl()):
|
||||
self.VerticalAxis=self.currX
|
||||
self.HorizontalAxis=self.currY
|
||||
if(self.HorizontalAxis<-1 or self.HorizontalAxis>1 or self.VerticalAxis<-1 or self.VerticalAxis>1):
|
||||
return
|
||||
self.resizedr(self.VerticalAxis,self.HorizontalAxis)
|
||||
|
||||
#if(self.AltPressed): # View Camera Transforms -> Maya style
|
||||
elif(1):
|
||||
#print "ALTPRESSED"
|
||||
if(self.PanConstantX<4096):
|
||||
self.PanConstantX= self.PanConstantX * 2
|
||||
self.PanConstantY= self.PanConstantY * 2
|
||||
self.ZoomConstant= self.ZoomConstant + 50
|
||||
if(self.MouseButton==1): # TrackBall rotation only for Perspective View
|
||||
if(self.CurrentQuad==4):
|
||||
pass
|
||||
elif(self.MouseButton==2): # Do Panning
|
||||
if(self.CurrentQuad==1): # Y and Z values change meanings for different cameras
|
||||
self.MoveCamera(-self.diffX*self.PanConstantX,0,-self.diffY*self.PanConstantY,self.CurrentQuad)
|
||||
elif(self.CurrentQuad==2):
|
||||
self.MoveCamera(-self.diffX*self.PanConstantX,-self.diffY*self.PanConstantY,0,self.CurrentQuad)
|
||||
elif(self.CurrentQuad==3):
|
||||
self.MoveCamera(0,self.diffX*self.PanConstantX,-self.diffY*self.PanConstantY,self.CurrentQuad)
|
||||
elif(self.CurrentQuad==4):
|
||||
pass
|
||||
elif(self.MouseButton==3): # Do Zoom
|
||||
if(self.CurrentQuad==1): # Y and Z values change meanings for different cameras
|
||||
#lens = OrthographicLens()
|
||||
#lens.setFilmSize(l,self.VP_height*200)
|
||||
#lens.setFilmOffset((self.VP_X2 + self.VP_X1) * 0.5, (self.VP_Y2 + self.VP_Y1) * 0.5)
|
||||
#lens.setNearFar(-1000, 1000)
|
||||
self.FrontWidth= self.FrontWidth + self.diffX
|
||||
self.FrontHeight= self.FrontHeight + self.diffX
|
||||
self.FrontWidth= self.FrontWidth + self.diffY
|
||||
self.FrontHeight= self.FrontHeight + self.diffY
|
||||
|
||||
if(self.FrontWidth<=0):
|
||||
Frontwidth=1
|
||||
if(self.FrontHeight<=0):
|
||||
FrontHeight=1
|
||||
self.frontCam.node().getLens().setFilmSize(self.FrontWidth,self.FrontHeight)
|
||||
self.resizedr(self.VerticalAxis,self.HorizontalAxis)
|
||||
elif(self.CurrentQuad==2):
|
||||
self.TopWidth= self.TopWidth + self.diffX
|
||||
self.TopHeight= self.TopHeight + self.diffX
|
||||
self.TopWidth= self.TopWidth + self.diffY
|
||||
self.TopHeight= self.TopHeight + self.diffY
|
||||
self.topCam.node().getLens().setFilmSize(self.TopWidth,self.TopHeight)
|
||||
self.resizedr(self.VerticalAxis,self.HorizontalAxis)
|
||||
elif(self.CurrentQuad==3):
|
||||
self.LeftWidth= self.LeftWidth + self.diffX
|
||||
self.LeftHeight= self.LeftHeight + self.diffX
|
||||
self.LeftWidth= self.LeftWidth + self.diffY
|
||||
self.LeftHeight= self.LeftHeight + self.diffY
|
||||
self.leftCam.node().getLens().setFilmSize(self.LeftWidth,self.LeftHeight)
|
||||
self.resizedr(self.VerticalAxis,self.HorizontalAxis)
|
||||
elif(self.CurrentQuad==4):
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
|
||||
self.oldX=self.currX
|
||||
self.oldY=self.currY
|
||||
return Task.cont
|
||||
|
||||
|
||||
|
||||
def MoveCamera(self,X_amt,Y_amt,Z_amt,quad):
|
||||
if(quad==1):
|
||||
self.frontCam.setPos(self.frontCam.getX()+X_amt,self.frontCam.getY()+Y_amt,self.frontCam.getZ()+Z_amt)
|
||||
elif(quad==2):
|
||||
self.topCam.setPos(self.topCam.getX()+X_amt,self.topCam.getY()+Y_amt,self.topCam.getZ()+Z_amt)
|
||||
elif(quad==3):
|
||||
self.leftCam.setPos(self.leftCam.getX()+X_amt,self.leftCam.getY()+Y_amt,self.leftCam.getZ()+Z_amt)
|
||||
elif(quad==4):
|
||||
self.perspectiveCam.setPos(self.perspectiveCam.getX()+X_amt,self.perspectiveCam.getY()+Y_amt,self.perspectiveCam.getZ()+Z_amt)
|
||||
|
||||
|
||||
|
||||
#View=QuadView()
|
||||
#run()
|
1708
build/nirai/panda3d/contrib/src/sceneeditor/sceneEditor.py
Normal file
1708
build/nirai/panda3d/contrib/src/sceneeditor/sceneEditor.py
Normal file
File diff suppressed because it is too large
Load diff
608
build/nirai/panda3d/contrib/src/sceneeditor/seAnimPanel.py
Normal file
608
build/nirai/panda3d/contrib/src/sceneeditor/seAnimPanel.py
Normal file
|
@ -0,0 +1,608 @@
|
|||
#################################################################
|
||||
# collisionWindow.py
|
||||
# Written by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#################################################################
|
||||
# Import Tkinter, Pmw, and the floater code from this directory tree.
|
||||
from direct.tkwidgets.AppShell import *
|
||||
from direct.showbase.TkGlobal import *
|
||||
from tkSimpleDialog import askfloat
|
||||
import string
|
||||
import math
|
||||
import types
|
||||
from direct.task import Task
|
||||
|
||||
FRAMES = 0
|
||||
SECONDS = 1
|
||||
|
||||
class AnimPanel(AppShell):
|
||||
#################################################################
|
||||
# This class will generate a animation panel for an actor
|
||||
# which user assigned. Inside this panel, instead of using actorInterval
|
||||
# or just simply calling the play function in Actor, we create a task to
|
||||
# set animation frame by frame using setPose.
|
||||
#################################################################
|
||||
# Override class variables
|
||||
appname = 'Anim Panel'
|
||||
frameWidth = 575
|
||||
frameHeight = 250
|
||||
usecommandarea = 0
|
||||
usestatusarea = 0
|
||||
index = 0
|
||||
dragMode = False
|
||||
rateList= ['1/24.0', '0.1', '0.5', '1.0', '2.0', '5.0' , '10.0']
|
||||
|
||||
|
||||
def __init__(self, aNode = None, parent = None, **kw):
|
||||
INITOPT = Pmw.INITOPT
|
||||
self.id = 'AnimPanel '+ aNode.getName()
|
||||
self.appname = self.id
|
||||
optiondefs = (
|
||||
('title', self.appname, None),
|
||||
('actor', aNode, None),
|
||||
('animList', [], None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
self.frameHeight = 300
|
||||
self.id = 'AnimPanel '+ aNode.getName()
|
||||
self.nodeName = aNode.getName()
|
||||
# Initialize the superclass
|
||||
AppShell.__init__(self)
|
||||
|
||||
# Execute option callbacks
|
||||
self.initialiseoptions(AnimPanel)
|
||||
|
||||
self.currTime = 0.0 # Initialize the start time
|
||||
self.animName = None
|
||||
|
||||
self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
|
||||
|
||||
def createInterface(self):
|
||||
# Handle to the toplevels interior
|
||||
interior = self.interior()
|
||||
menuBar = self.menuBar
|
||||
|
||||
menuBar.addmenu('Anim', 'Anim Panel Operations')
|
||||
|
||||
# Reset all actor controls
|
||||
menuBar.addmenuitem('File', 'command',
|
||||
'Load Animation',
|
||||
label = 'Load Animation',
|
||||
command = self.loadAnimation)
|
||||
menuBar.addmenuitem('Anim', 'command',
|
||||
'Set actor controls to t = 0.0',
|
||||
label = 'Jump all to zero',
|
||||
command = self.resetAllToZero)
|
||||
menuBar.addmenuitem('Anim', 'command',
|
||||
'Set Actor controls to end time',
|
||||
label = 'Jump all to end time',
|
||||
command = self.resetAllToEnd)
|
||||
menuBar.addmenuitem('Anim', 'separator')
|
||||
menuBar.addmenuitem('Anim', 'command',
|
||||
'Play Current Animation',
|
||||
label = 'Play',
|
||||
command = self.play)
|
||||
menuBar.addmenuitem('Anim', 'command',
|
||||
'Stop Current Animation',
|
||||
label = 'stop',
|
||||
command = self.stop)
|
||||
|
||||
# Create a frame to hold all the actor controls
|
||||
actorFrame = Frame(interior)
|
||||
name_label = Label(actorFrame, text= self.nodeName,font=('MSSansSerif', 16),
|
||||
relief = SUNKEN, borderwidth=3)
|
||||
name_label.place(x=5,y=5,anchor=NW)
|
||||
Label(actorFrame, text= "Animation:", font=('MSSansSerif', 12)).place(x=140,y=5,anchor=NW)
|
||||
Label(actorFrame, text= "Play Rate:", font=('MSSansSerif', 12)).place(x=140,y=35,anchor=NW)
|
||||
self['animList'] = self['actor'].getAnimNames()
|
||||
self.AnimEntry = self.createcomponent(
|
||||
'AnimationMenu', (), None,
|
||||
Pmw.ComboBox, (actorFrame,),
|
||||
labelpos = W, entry_width = 20, selectioncommand = self.setAnimation,
|
||||
scrolledlist_items = self['animList'])
|
||||
self.AnimEntry.place(x=240,y=10,anchor=NW)
|
||||
|
||||
|
||||
self.playRateEntry = self.createcomponent(
|
||||
'playRateMenu', (), None,
|
||||
Pmw.ComboBox, (actorFrame,),
|
||||
labelpos = W, entry_width = 20, selectioncommand = self.setPlayRate,
|
||||
scrolledlist_items = self.rateList)
|
||||
self.playRateEntry.place(x=240,y=40,anchor=NW)
|
||||
self.playRateEntry.selectitem('1.0')
|
||||
|
||||
### Loop checkbox
|
||||
Label(actorFrame, text= "Loop:", font=('MSSansSerif', 12)).place(x=420,y=05,anchor=NW)
|
||||
|
||||
self.loopVar = IntVar()
|
||||
self.loopVar.set(0)
|
||||
self.loopButton = self.createcomponent(
|
||||
'loopButton', (), None,
|
||||
Checkbutton, (actorFrame,),
|
||||
variable = self.loopVar)
|
||||
self.loopButton.place(x=470,y=7,anchor=NW)
|
||||
|
||||
### Display Frames/Seconds
|
||||
Label(actorFrame, text= "Frame/Second:", font=('MSSansSerif', 11)).place(x=5,y=75,anchor=NW)
|
||||
|
||||
self.unitsVar = IntVar()
|
||||
self.unitsVar.set(FRAMES)
|
||||
self.displayButton = self.createcomponent(
|
||||
'displayButton', (), None,
|
||||
Checkbutton, (actorFrame,),
|
||||
command = self.updateDisplay,
|
||||
variable = self.unitsVar)
|
||||
self.displayButton.place(x=120,y=77,anchor=NW)
|
||||
|
||||
## scale control
|
||||
frameFrame = Frame(actorFrame, relief = SUNKEN, bd = 1)
|
||||
self.minLabel = self.createcomponent(
|
||||
'minLabel', (), 'sLabel',
|
||||
Label, (frameFrame,),
|
||||
text = 0)
|
||||
self.minLabel.pack(side = LEFT)
|
||||
|
||||
self.frameControl = self.createcomponent(
|
||||
'scale', (), None,
|
||||
Scale, (frameFrame,),
|
||||
from_ = 0, to = 24, resolution = 1.0,
|
||||
command = self.goTo, length = 500,
|
||||
orient = HORIZONTAL, showvalue = 1)
|
||||
self.frameControl.pack(side = LEFT, expand = 1)
|
||||
self.frameControl.bind('<Button-1>', self.onPress)
|
||||
self.frameControl.bind('<ButtonRelease-1>', self.onRelease)
|
||||
|
||||
self.maxLabel = self.createcomponent(
|
||||
'maxLabel', (), 'sLabel',
|
||||
Label, (frameFrame,),
|
||||
text = 24)
|
||||
self.maxLabel.pack(side = LEFT)
|
||||
frameFrame.pack(side = LEFT, expand = 1, fill = X)
|
||||
|
||||
## button contorl
|
||||
ButtomFrame = Frame(actorFrame, relief = SUNKEN, bd = 1,borderwidth=5)
|
||||
self.toStartButton = self.createcomponent(
|
||||
'toStart', (), None,
|
||||
Button, (ButtomFrame,),
|
||||
text = '<<',
|
||||
width = 8,
|
||||
command = self.resetAllToZero)
|
||||
self.toStartButton.pack(side = LEFT, expand = 1, fill = X)
|
||||
|
||||
self.playButton = self.createcomponent(
|
||||
'playButton', (), None,
|
||||
Button, (ButtomFrame,),
|
||||
text = 'Play', width = 8,
|
||||
command = self.play)
|
||||
self.playButton.pack(side = LEFT, expand = 1, fill = X)
|
||||
|
||||
self.stopButton = self.createcomponent(
|
||||
'stopButton', (), None,
|
||||
Button, (ButtomFrame,),
|
||||
text = 'Stop', width = 8, state=DISABLED,
|
||||
command = self.stop)
|
||||
self.stopButton.pack(side = LEFT, expand = 1, fill = X)
|
||||
|
||||
self.toEndButton = self.createcomponent(
|
||||
'toEnd', (), None,
|
||||
Button, (ButtomFrame,),
|
||||
text = '>>',
|
||||
width = 8,
|
||||
command = self.resetAllToEnd)
|
||||
self.toEndButton.pack(side = LEFT, expand = 1, fill = X)
|
||||
|
||||
ButtomFrame.place(anchor=NW,x=5,y=165)
|
||||
|
||||
self.removeButton = self.createcomponent(
|
||||
'Remove Animation', (), None,
|
||||
Button, (actorFrame,),
|
||||
text = 'Remove This Animation', width = 20,
|
||||
command = self.removeAnim)
|
||||
self.removeButton.place(anchor=NW,x=5,y=220)
|
||||
|
||||
self.loadButton = self.createcomponent(
|
||||
'Load Animation', (), None,
|
||||
Button, (actorFrame,),
|
||||
text = 'Load New Animation', width = 20,
|
||||
command = self.loadAnimation)
|
||||
self.loadButton.place(anchor=NW,x=180,y=220)
|
||||
|
||||
# Now pack the actor frame
|
||||
actorFrame.pack(expand = 1, fill = BOTH)
|
||||
|
||||
def updateList(self):
|
||||
#################################################################
|
||||
# updateList(self)
|
||||
# This function will update the list of animations that the Actor
|
||||
# currently has into the combo box widget.
|
||||
#################################################################
|
||||
self.ignore('DataH_loadFinish'+self.nodeName)
|
||||
del self.loaderWindow
|
||||
self['animList'] = self['actor'].getAnimNames()
|
||||
animL = self['actor'].getAnimNames()
|
||||
self.AnimEntry.setlist(animL)
|
||||
|
||||
|
||||
def removeAnim(self):
|
||||
#################################################################
|
||||
# removeAnim(self)
|
||||
# This function will stop the animation and get the name of animation
|
||||
# which user wish to remove from the panel. Then, it will send out
|
||||
# a message to dataHolder to remove the target animation.
|
||||
# And in the same time, it will start waiting a return message to
|
||||
# make sure that target animation has been removed.
|
||||
#################################################################
|
||||
name = self.AnimEntry.get()
|
||||
if taskMgr.hasTaskNamed(self.id + '_UpdateTask'):
|
||||
self.stop()
|
||||
self.accept('DataH_removeAnimFinish'+self.nodeName,self.afterRemove)
|
||||
messenger.send('AW_removeAnim',[self['actor'],name])
|
||||
return
|
||||
|
||||
def afterRemove(self):
|
||||
#################################################################
|
||||
# afterRemove(self)
|
||||
# This function will be called once panel has received the return
|
||||
# message from dataHolder. This function will call setList to
|
||||
# reset the list of Animations
|
||||
#################################################################
|
||||
self.ignore('DataH_removeAnimFinish'+self.nodeName)
|
||||
self['animList'] = self['actor'].getAnimNames()
|
||||
animL = self['actor'].getAnimNames()
|
||||
self.AnimEntry.setlist(animL)
|
||||
print '-----',animL
|
||||
return
|
||||
|
||||
def loadAnimation(self):
|
||||
#################################################################
|
||||
# loadAnimation(self)
|
||||
# This function will open a dialog window to require user to input
|
||||
# the animation he wants to load in for this actor.
|
||||
#################################################################
|
||||
self.loaderWindow = LoadAnimPanel(aNode=self['actor'])
|
||||
self.accept('DataH_loadFinish'+self.nodeName,self.updateList)
|
||||
return
|
||||
|
||||
def play(self):
|
||||
#################################################################
|
||||
# play(self)
|
||||
# This function will be called when user click on the "play" button.
|
||||
# First, this function will initialize all parameter that the actual
|
||||
# play task need to run and add the play task into the taskMgr.
|
||||
#################################################################
|
||||
self.animName = self.AnimEntry.get()
|
||||
if self.animName in self['animList']:
|
||||
animName = self.AnimEntry.get()
|
||||
self.playButton.config(state=DISABLED)
|
||||
self.lastT = globalClock.getFrameTime()
|
||||
taskMgr.add(self.playTask, self.id + '_UpdateTask')
|
||||
self.stopButton.config(state=NORMAL)
|
||||
else:
|
||||
print '----Illegal Animaion name!!', self.animName
|
||||
return
|
||||
|
||||
def playTask(self, task):
|
||||
#################################################################
|
||||
# playTask(self, task)
|
||||
# This task will record time by each frame
|
||||
# In fact it is just a clock keeper.
|
||||
# If the current frame time over the max long of the animation,
|
||||
# it will reset the timer.
|
||||
# Anyway, this function will call gotoT by each frame.
|
||||
#################################################################
|
||||
fLoop = self.loopVar.get()
|
||||
currT = globalClock.getFrameTime()
|
||||
deltaT = currT - self.lastT
|
||||
self.lastT = currT
|
||||
if self.dragMode:
|
||||
return Task.cont
|
||||
self.currTime = self.currTime + deltaT
|
||||
if (self.currTime > self.maxSeconds):
|
||||
if fLoop:
|
||||
self.currTime = self.currTime%self.duration
|
||||
self.gotoT(self.currTime)
|
||||
else:
|
||||
self.currTime = 0.0
|
||||
self.gotoT(0.0)
|
||||
self.playButton.config(state=NORMAL)
|
||||
self.stopButton.config(state=DISABLED)
|
||||
return Task.done
|
||||
else:
|
||||
self.gotoT(self.currTime)
|
||||
return Task.cont
|
||||
|
||||
def stop(self):
|
||||
#################################################################
|
||||
# stop(self)
|
||||
# This function will remove the play task from taskMgr when user
|
||||
# click on the "Stop" button
|
||||
#################################################################
|
||||
taskMgr.remove(self.id + '_UpdateTask')
|
||||
self.playButton.config(state=NORMAL)
|
||||
self.stopButton.config(state=DISABLED)
|
||||
return
|
||||
|
||||
def setAnimation(self, animation):
|
||||
#################################################################
|
||||
# setAnimation(self, animation)
|
||||
# This function will be called each time when user change
|
||||
# the current animation. Most important thing this function do is
|
||||
# to recalculate all variables to fit the selected animation
|
||||
#################################################################
|
||||
self.animName = self.AnimEntry.get()
|
||||
playRate = '%0.1f' % self['actor'].getPlayRate(self.animName)
|
||||
if playRate not in self.rateList:
|
||||
def strCmp(a, b):
|
||||
return cmp(eval(a), eval(b))
|
||||
self.rateList.append(playRate)
|
||||
self.rateList.sort(strCmp)
|
||||
self.playRateEntry.reset(self.rateList)
|
||||
self.playRateEntry.selectitem(playRate)
|
||||
self.currTime = 0.0
|
||||
self.frameControl.set(0)
|
||||
self.updateDisplay()
|
||||
return
|
||||
|
||||
def setPlayRate(self,rate):
|
||||
#################################################################
|
||||
# setPlayRate(self, rate)
|
||||
# This function will be called each time when user changes the current play rate.
|
||||
#################################################################
|
||||
self.animName = self.AnimEntry.get()
|
||||
if self.animName in self['animList']:
|
||||
self['actor'].setPlayRate(eval(rate), self.animName)
|
||||
self.updateDisplay()
|
||||
return
|
||||
|
||||
def updateDisplay(self):
|
||||
#################################################################
|
||||
# updateDisplay(self)
|
||||
# This function will be called whenever something has been changed
|
||||
# on the panel. In here we will re-new all widgets on the panel to
|
||||
# correct value.
|
||||
#################################################################
|
||||
self.fps = self['actor'].getFrameRate(self.animName)
|
||||
self.duration = self['actor'].getDuration(self.animName)
|
||||
self.maxFrame = self['actor'].getNumFrames(self.animName) - 1
|
||||
self.maxSeconds = self.duration
|
||||
if self.unitsVar.get() == FRAMES:
|
||||
fromFrame = 0
|
||||
toFrame = self.maxFrame
|
||||
self.minLabel['text'] = fromFrame
|
||||
self.maxLabel['text'] = toFrame
|
||||
self.frameControl.configure(from_ = fromFrame,
|
||||
to = toFrame,
|
||||
resolution = 1.0)
|
||||
else:
|
||||
self.minLabel['text'] = '0.0'
|
||||
self.maxLabel['text'] = "%.2f" % self.duration
|
||||
self.frameControl.configure(from_ = 0.0,
|
||||
to = self.duration,
|
||||
resolution = 0.01)
|
||||
|
||||
def gotoT(self,time):
|
||||
#################################################################
|
||||
# gotoT(self, time)
|
||||
# calculate the right parameter which will be send to set Frame
|
||||
# Control slider, which is the real place we play the animation.
|
||||
#################################################################
|
||||
if self.unitsVar.get() == FRAMES:
|
||||
self.frameControl.set(time * self.fps)
|
||||
else:
|
||||
self.frameControl.set(time)
|
||||
return
|
||||
|
||||
def goTo(self,frame):
|
||||
#################################################################
|
||||
# goto(self, frame)
|
||||
# Call back function for the frame control slider.
|
||||
# This function will set the animation by the value on the slider.
|
||||
#
|
||||
# This function is the real function we "play" the animation.
|
||||
#
|
||||
#################################################################
|
||||
if self.animName in self['animList']:
|
||||
# Convert scale value to float
|
||||
frame = string.atof(frame)
|
||||
# Now convert t to seconds for offset calculations
|
||||
if self.unitsVar.get() == FRAMES:
|
||||
frame = frame / self.fps
|
||||
if self.dragMode:
|
||||
# If user is clicking on the slider and is draging the bar, reset the global timer.
|
||||
self.currTime = frame
|
||||
self['actor'].pose(self.animName,
|
||||
min(self.maxFrame, int(frame * self.fps)))
|
||||
return
|
||||
|
||||
def onRelease(self,frame):
|
||||
#################################################################
|
||||
# onRelease(self, frame)
|
||||
# disable the dragMode when user releases the bar on the slider.
|
||||
#################################################################
|
||||
self.dragMode = False
|
||||
return
|
||||
|
||||
def onPress(self,frame):
|
||||
#################################################################
|
||||
# onPress(self, frame)
|
||||
# enable the dragMode when user press the bar on the slider.
|
||||
#################################################################
|
||||
self.dragMode = True
|
||||
return
|
||||
|
||||
def resetAllToZero(self):
|
||||
#################################################################
|
||||
# resetAllToZero(self)
|
||||
# reset the global timer to zero and also move the slider to zero.
|
||||
# This will also reset the actor to the zero frame of current animation
|
||||
#################################################################
|
||||
self.currTime = 0.0
|
||||
self.gotoT(0)
|
||||
return
|
||||
|
||||
def resetAllToEnd(self):
|
||||
#################################################################
|
||||
# resetAllToEnd(self)
|
||||
# set the global timer to the end of current animation and
|
||||
# also move the slider to the end.
|
||||
#################################################################
|
||||
self.currTime = self.maxSeconds
|
||||
self.gotoT(self.duration)
|
||||
return
|
||||
|
||||
def onDestroy(self, event):
|
||||
if taskMgr.hasTaskNamed(self.id + '_UpdateTask'):
|
||||
taskMgr.remove(self.id + '_UpdateTask')
|
||||
self.ignore('DataH_loadFinish')
|
||||
messenger.send('AW_close',[self.nodeName])
|
||||
'''
|
||||
If you have open any thing, please rewrite here!
|
||||
'''
|
||||
pass
|
||||
|
||||
class LoadAnimPanel(AppShell):
|
||||
#################################################################
|
||||
# LoadAnimPanel(AppShell)
|
||||
# This class will open a dialog to ask user to input names and
|
||||
# file paths of animations
|
||||
#################################################################
|
||||
# Override class variables
|
||||
appname = 'Load Animation'
|
||||
frameWidth = 575
|
||||
frameHeight = 200
|
||||
usecommandarea = 0
|
||||
usestatusarea = 0
|
||||
index = 0
|
||||
## Anim name : File Path
|
||||
|
||||
def __init__(self, aNode = None, parent = None, **kw):
|
||||
INITOPT = Pmw.INITOPT
|
||||
self.id = 'Load Animation '+ aNode.getName()
|
||||
self.appname = self.id
|
||||
self.animDic = {}
|
||||
self.animList = []
|
||||
optiondefs = (
|
||||
('title', self.appname, None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
self.frameHeight = 300
|
||||
self.nodeName = aNode.getName()
|
||||
self.Actor = aNode
|
||||
# Initialize the superclass
|
||||
AppShell.__init__(self)
|
||||
|
||||
# Execute option callbacks
|
||||
self.initialiseoptions(LoadAnimPanel)
|
||||
|
||||
def createInterface(self):
|
||||
self.menuBar.destroy()
|
||||
interior = self.interior()
|
||||
mainFrame = Frame(interior)
|
||||
self.inputZone = Pmw.Group(mainFrame, tag_text='File Setting')
|
||||
self.inputZone.pack(fill='both',expand=1)
|
||||
settingFrame = self.inputZone.interior()
|
||||
Label(settingFrame,text='Anim Name').place(anchor=NW,x=60,y=5)
|
||||
Label(settingFrame,text='File Path').place(anchor=NW,x=205,y=5)
|
||||
self.AnimName_1 = self.createcomponent(
|
||||
'Anim Name List', (), None,
|
||||
Pmw.ComboBox, (settingFrame,),label_text='Anim :',
|
||||
labelpos = W, entry_width = 10, selectioncommand = self.selectAnim,
|
||||
scrolledlist_items = self.animList)
|
||||
self.AnimFile_1 = Pmw.EntryField(settingFrame,value='')
|
||||
self.AnimFile_1.component('entry').config(width=20)
|
||||
self.AnimName_1.place(anchor=NW,x=10,y=25)
|
||||
self.AnimFile_1.place(anchor=NW,x=140,y=25)
|
||||
self.Browse_1 = self.createcomponent(
|
||||
'File Browser1', (), None,
|
||||
Button, (mainFrame,),
|
||||
text = 'Browse...',
|
||||
command = self.Browse_1)
|
||||
self.Browse_1.place(anchor=NW,x=270,y=38)
|
||||
|
||||
self.addIntoButton = self.createcomponent(
|
||||
'Load Add', (), None,
|
||||
Button, (mainFrame,),
|
||||
text = 'Add to Load',
|
||||
command = self.addIntoList)
|
||||
self.addIntoButton.place(anchor=NW,x=345,y=38)
|
||||
|
||||
att_label = Label(mainFrame, font=('MSSansSerif', 10),
|
||||
text= "Attention! Animations won't be loaded in before you press the 'OK' button below!")
|
||||
att_label.place(anchor=NW,x=10,y=80)
|
||||
|
||||
self.button_ok = Button(mainFrame, text="OK", command=self.ok_press,width=10)
|
||||
self.button_ok.pack(fill=BOTH,expand=0,side=RIGHT)
|
||||
|
||||
mainFrame.pack(expand = 1, fill = BOTH)
|
||||
|
||||
|
||||
|
||||
def onDestroy(self, event):
|
||||
messenger.send('AWL_close',[self.nodeName])
|
||||
'''
|
||||
If you have open any thing, please rewrite here!
|
||||
'''
|
||||
pass
|
||||
|
||||
def selectAnim(self,name):
|
||||
#################################################################
|
||||
# selectAnim(self, name)
|
||||
# This function will be called if user select an animation on the list.
|
||||
#################################################################
|
||||
if name in self.animDic:
|
||||
self.AnimFile_1.setvalue = self.animDic[name]
|
||||
return
|
||||
|
||||
def Browse_1(self):
|
||||
#################################################################
|
||||
# Browse_1(self)
|
||||
# when the browse button pused, this function will be called.
|
||||
# Do nothing but open a file dialog for user to set the path to target file
|
||||
# Then, set the path back to the entry on the panel.
|
||||
#################################################################
|
||||
AnimFilename = askopenfilename(
|
||||
defaultextension = '.egg',
|
||||
filetypes = (('Egg Files', '*.egg'),
|
||||
('Bam Files', '*.bam'),
|
||||
('All files', '*')),
|
||||
initialdir = '.',
|
||||
title = 'File Path for Anim 1',
|
||||
parent = self.parent)
|
||||
if AnimFilename:
|
||||
self.AnimFile_1.setvalue(AnimFilename)
|
||||
return
|
||||
|
||||
def addIntoList(self):
|
||||
#################################################################
|
||||
# addIntoList(self)
|
||||
# This function will be called each time when user click on the
|
||||
# "Add to Load" button. This function will read the current data
|
||||
# on the panel into a dictionary. then reset the list of the animation
|
||||
# name list on this panel.(not the one in the animation panel...)
|
||||
#
|
||||
# This function won't load any animation....
|
||||
#
|
||||
#################################################################
|
||||
name = self.AnimName_1.get()
|
||||
self.animDic[name] = Filename.fromOsSpecific(self.AnimFile_1.getvalue()).getFullpath()
|
||||
if name in self.animList:
|
||||
pass
|
||||
else:
|
||||
self.animList.append(name)
|
||||
self.AnimName_1.setlist(self.animList)
|
||||
print self.animDic
|
||||
return
|
||||
|
||||
def ok_press(self):
|
||||
#################################################################
|
||||
# ok_press(Self)
|
||||
# This functiion will be called when user click on the "OK"
|
||||
# button. This function will send a message along with the animation
|
||||
# file we wish to load for this actor.
|
||||
# Then, it will close the panel itself.
|
||||
#################################################################
|
||||
messenger.send('AW_AnimationLoad',[self.Actor,self.animDic])
|
||||
#print self.animDic
|
||||
self.quit()
|
||||
return
|
666
build/nirai/panda3d/contrib/src/sceneeditor/seBlendAnimPanel.py
Normal file
666
build/nirai/panda3d/contrib/src/sceneeditor/seBlendAnimPanel.py
Normal file
|
@ -0,0 +1,666 @@
|
|||
#################################################################
|
||||
# collisionWindow.py
|
||||
# Written by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#################################################################
|
||||
# Import Tkinter, Pmw, and the floater code from this directory tree.
|
||||
from direct.tkwidgets.AppShell import *
|
||||
from direct.showbase.TkGlobal import *
|
||||
from tkSimpleDialog import askfloat
|
||||
import string
|
||||
import math
|
||||
import types
|
||||
from direct.task import Task
|
||||
|
||||
FRAMES = 0
|
||||
SECONDS = 1
|
||||
|
||||
|
||||
#####################################################################################
|
||||
# BlendAnimPanel(AppShell)
|
||||
# This Panel will allow user to blend tow animations
|
||||
# that have already been loaded for this actor.
|
||||
# user can play and manipulate this blended animation
|
||||
# just like in the animation panel. And, they can save this blended animation.
|
||||
#####################################################################################
|
||||
class BlendAnimPanel(AppShell):
|
||||
# Override class variables
|
||||
appname = 'Blend Anim Panel'
|
||||
frameWidth = 575
|
||||
frameHeight = 450
|
||||
usecommandarea = 0
|
||||
usestatusarea = 0
|
||||
index = 0
|
||||
dragMode = False
|
||||
blendRatio = 0
|
||||
rateList= ['1/24.0', '0.1', '0.5', '1.0', '2.0', '5.0' , '10.0']
|
||||
enableBlend = False
|
||||
currentBlendName = None
|
||||
|
||||
|
||||
def __init__(self, aNode = None, blendDict={}, parent = None, **kw):
|
||||
INITOPT = Pmw.INITOPT
|
||||
self.id = 'BlendAnimPanel '+ aNode.getName()
|
||||
self.appname = self.id
|
||||
self.actorNode = aNode
|
||||
self.blendDict = blendDict.copy()
|
||||
if len(blendDict)>0:
|
||||
self.blendList = blendDict.keys()
|
||||
else:
|
||||
self.blendList = []
|
||||
optiondefs = (
|
||||
('title', self.appname, None),
|
||||
('actor', aNode, None),
|
||||
('animList', [], None),
|
||||
('blendAnimList', self.blendList, None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
self.id = 'Blend AnimPanel '+ aNode.getName()
|
||||
self.nodeName = aNode.getName()
|
||||
# Initialize the superclass
|
||||
AppShell.__init__(self)
|
||||
|
||||
# Execute option callbacks
|
||||
self.initialiseoptions(BlendAnimPanel)
|
||||
|
||||
self.currTime = 0.0
|
||||
self.animNameA = None
|
||||
self.animNameB = None
|
||||
|
||||
self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
|
||||
|
||||
def createInterface(self):
|
||||
# Handle to the toplevels interior
|
||||
interior = self.interior()
|
||||
self.menuBar.destroy()
|
||||
|
||||
# show the actor's name
|
||||
actorFrame = Frame(interior)
|
||||
name_label = Label(actorFrame, text= self.nodeName,font=('MSSansSerif', 14),
|
||||
relief = SUNKEN, borderwidth=3)
|
||||
name_label.pack(side = TOP, expand = False)
|
||||
actorFrame.pack(side = TOP, expand = False, fill = X)
|
||||
|
||||
# Create a frame to show is there any ore-blended animation and save, edit, rename button.
|
||||
group = Pmw.Group(interior, tag_pyclass=None)
|
||||
actorFrame = group.interior()
|
||||
group.pack(side = TOP, expand = False, fill = X)
|
||||
|
||||
Label(actorFrame, text= "Blended:", font=('MSSansSerif', 10)).pack(side=LEFT)
|
||||
self.blendAnimEntry = self.createcomponent(
|
||||
'Blended Animation', (), None,
|
||||
Pmw.ComboBox, (actorFrame,),
|
||||
labelpos = W, entry_width = 20, selectioncommand = self.setBlendAnim,
|
||||
scrolledlist_items = self['blendAnimList'])
|
||||
self.blendAnimEntry.pack(side=LEFT)
|
||||
|
||||
Label(actorFrame, text= " ", font=('MSSansSerif', 10)).pack(side=LEFT)
|
||||
|
||||
button = Button(actorFrame, text="Save", font=('MSSansSerif', 10),width = 12,
|
||||
command = self.saveButtonPushed).pack(side=LEFT)
|
||||
button = Button(actorFrame, text="Remove", font=('MSSansSerif', 10),width = 12,
|
||||
command = self.removeButtonPushed).pack(side=LEFT)
|
||||
button = Button(actorFrame, text="Rename", font=('MSSansSerif', 10),width = 12,
|
||||
command = self.renameButtonPushed).pack(side=LEFT)
|
||||
|
||||
actorFrame.pack(side = TOP, expand = False, fill = X)
|
||||
|
||||
# Create a frame to hold all the animation setting
|
||||
group = Pmw.Group(interior, tag_pyclass=None)
|
||||
actorFrame = group.interior()
|
||||
group.pack(side = TOP, expand = False, fill = X)
|
||||
Label(actorFrame, text= "Animation A:", font=('MSSansSerif', 10)).pack(side=LEFT)
|
||||
self['animList'] = self['actor'].getAnimNames()
|
||||
self.AnimEntryA = self.createcomponent(
|
||||
'AnimationMenuA', (), None,
|
||||
Pmw.ComboBox, (actorFrame,),
|
||||
labelpos = W, entry_width = 20, entry_state = DISABLED,
|
||||
selectioncommand = lambda name, a = 'a' : self.setAnimation(name, AB=a),
|
||||
scrolledlist_items = self['animList'])
|
||||
self.AnimEntryA.pack(side=LEFT)
|
||||
|
||||
Label(actorFrame, text= " ", font=('MSSansSerif', 10)).pack(side=LEFT,)
|
||||
Label(actorFrame, text= "Animation B:", font=('MSSansSerif', 10)).pack(side=LEFT)
|
||||
self['animList'] = self['actor'].getAnimNames()
|
||||
self.AnimEntryB = self.createcomponent(
|
||||
'AnimationMenuB', (), None,
|
||||
Pmw.ComboBox, (actorFrame,),
|
||||
labelpos = W, entry_width = 20, entry_state = DISABLED,
|
||||
selectioncommand = lambda name, a = 'b' : self.setAnimation(name, AB=a),
|
||||
scrolledlist_items = self['animList'])
|
||||
self.AnimEntryB.pack(side=LEFT)
|
||||
actorFrame.pack(side = TOP, expand = False, fill = X)
|
||||
|
||||
### Blend Enable checkbox
|
||||
actorFrame = Frame(interior, relief = SUNKEN, bd = 1)
|
||||
Label(actorFrame, text= "Enable Blending:", font=('MSSansSerif', 10)).pack(side=LEFT,)
|
||||
self.blendVar = IntVar()
|
||||
self.blendVar.set(0)
|
||||
self.blendButton = self.createcomponent(
|
||||
'blendButton', (), None,
|
||||
Checkbutton, (actorFrame,),
|
||||
variable = self.blendVar,
|
||||
command = self.toggleBlend)
|
||||
self.blendButton.pack(side=LEFT)
|
||||
actorFrame.pack(side = TOP, expand = False, fill = X)
|
||||
|
||||
## Ratio control
|
||||
actorFrame = Frame(interior)
|
||||
frameFrame = Frame(actorFrame, relief = SUNKEN, bd = 1)
|
||||
minRatioLabel = self.createcomponent(
|
||||
'minRatioLabel', (), 'sLabel',
|
||||
Label, (frameFrame,),
|
||||
text = 0.00)
|
||||
minRatioLabel.pack(side = LEFT)
|
||||
|
||||
self.ratioControl = self.createcomponent(
|
||||
'ratio', (), None,
|
||||
Scale, (frameFrame,),
|
||||
from_ = 0.0, to = 1.0, resolution = 0.01,
|
||||
command = self.setRatio, length = 500,
|
||||
orient = HORIZONTAL, showvalue = 1)
|
||||
self.ratioControl.pack(side = LEFT, expand = 1)
|
||||
self.ratioControl.set(1.0)
|
||||
|
||||
self.maxRatioLabel = self.createcomponent(
|
||||
'maxRatioLabel', (), 'sLabel',
|
||||
Label, (frameFrame,),
|
||||
text = 1.00)
|
||||
self.maxRatioLabel.pack(side = LEFT)
|
||||
frameFrame.pack(side = LEFT, expand = 1, fill = X)
|
||||
actorFrame.pack(side = TOP, expand = True, fill = X)
|
||||
|
||||
###################################################################################
|
||||
###################################################################################
|
||||
actorFrame = Frame(interior)
|
||||
Label(actorFrame, text= "Play Rate:", font=('MSSansSerif', 10)).pack(side=LEFT)
|
||||
self.playRateEntry = self.createcomponent(
|
||||
'playRateMenu', (), None,
|
||||
Pmw.ComboBox, (actorFrame,),
|
||||
labelpos = W, entry_width = 20, selectioncommand = self.setPlayRate,
|
||||
scrolledlist_items = self.rateList)
|
||||
self.playRateEntry.pack(side=LEFT)
|
||||
self.playRateEntry.selectitem('1.0')
|
||||
|
||||
### Loop checkbox
|
||||
Label(actorFrame, text= " ", font=('MSSansSerif', 10)).pack(side=LEFT,)
|
||||
Label(actorFrame, text= "Loop:", font=('MSSansSerif', 10)).pack(side=LEFT,)
|
||||
|
||||
self.loopVar = IntVar()
|
||||
self.loopVar.set(0)
|
||||
self.loopButton = self.createcomponent(
|
||||
'loopButton', (), None,
|
||||
Checkbutton, (actorFrame,),
|
||||
variable = self.loopVar)
|
||||
self.loopButton.pack(side=LEFT)
|
||||
|
||||
actorFrame.pack(side = TOP, expand = True, fill = X)
|
||||
|
||||
|
||||
|
||||
### Display Frames/Seconds
|
||||
actorFrame = Frame(interior)
|
||||
|
||||
Label(actorFrame, text= "Frame/Second:", font=('MSSansSerif', 10)).pack(side=LEFT)
|
||||
|
||||
self.unitsVar = IntVar()
|
||||
self.unitsVar.set(FRAMES)
|
||||
self.displayButton = self.createcomponent(
|
||||
'displayButton', (), None,
|
||||
Checkbutton, (actorFrame,),
|
||||
command = self.updateDisplay,
|
||||
variable = self.unitsVar)
|
||||
self.displayButton.pack(side=LEFT)
|
||||
|
||||
actorFrame.pack(side = TOP, expand = True, fill = X)
|
||||
|
||||
## scale control
|
||||
actorFrame = Frame(interior)
|
||||
frameFrame = Frame(actorFrame, relief = SUNKEN, bd = 1)
|
||||
self.minLabel = self.createcomponent(
|
||||
'minLabel', (), 'sLabel',
|
||||
Label, (frameFrame,),
|
||||
text = 0)
|
||||
self.minLabel.pack(side = LEFT)
|
||||
|
||||
self.frameControl = self.createcomponent(
|
||||
'scale', (), None,
|
||||
Scale, (frameFrame,),
|
||||
from_ = 0, to = 24, resolution = 1.0,
|
||||
command = self.goTo, length = 500,
|
||||
orient = HORIZONTAL, showvalue = 1)
|
||||
self.frameControl.pack(side = LEFT, expand = 1)
|
||||
self.frameControl.bind('<Button-1>', self.onPress)
|
||||
self.frameControl.bind('<ButtonRelease-1>', self.onRelease)
|
||||
|
||||
self.maxLabel = self.createcomponent(
|
||||
'maxLabel', (), 'sLabel',
|
||||
Label, (frameFrame,),
|
||||
text = 24)
|
||||
self.maxLabel.pack(side = LEFT)
|
||||
frameFrame.pack(side = LEFT, expand = 1, fill = X)
|
||||
actorFrame.pack(side = TOP, expand = True, fill = X)
|
||||
|
||||
## button contorl
|
||||
actorFrame = Frame(interior)
|
||||
ButtomFrame = Frame(actorFrame, relief = SUNKEN, bd = 1,borderwidth=5)
|
||||
self.toStartButton = self.createcomponent(
|
||||
'toStart', (), None,
|
||||
Button, (ButtomFrame,),
|
||||
text = '<<',
|
||||
width = 8,
|
||||
command = self.resetAllToZero)
|
||||
self.toStartButton.pack(side = LEFT, expand = 1, fill = X)
|
||||
|
||||
self.playButton = self.createcomponent(
|
||||
'playButton', (), None,
|
||||
Button, (ButtomFrame,),
|
||||
text = 'Play', width = 8,
|
||||
command = self.play)
|
||||
self.playButton.pack(side = LEFT, expand = 1, fill = X)
|
||||
|
||||
self.stopButton = self.createcomponent(
|
||||
'stopButton', (), None,
|
||||
Button, (ButtomFrame,),
|
||||
text = 'Stop', width = 8, state=DISABLED,
|
||||
command = self.stop)
|
||||
self.stopButton.pack(side = LEFT, expand = 1, fill = X)
|
||||
|
||||
self.toEndButton = self.createcomponent(
|
||||
'toEnd', (), None,
|
||||
Button, (ButtomFrame,),
|
||||
text = '>>',
|
||||
width = 8,
|
||||
command = self.resetAllToEnd)
|
||||
self.toEndButton.pack(side = LEFT, expand = 1, fill = X)
|
||||
|
||||
ButtomFrame.pack(side = TOP, expand = True, fill = X)
|
||||
actorFrame.pack(expand = 1, fill = BOTH)
|
||||
|
||||
def updateList(self):
|
||||
#################################################################
|
||||
# updateList(self)
|
||||
# This will reset the list of all animations that this actor has
|
||||
# to the animation entry A and B.
|
||||
#################################################################
|
||||
self['animList'] = self['actor'].getAnimNames()
|
||||
animL = self['actor'].getAnimNames()
|
||||
self.AnimEntryA.setlist(animL)
|
||||
self.AnimEntryB.setlist(animL)
|
||||
|
||||
def play(self):
|
||||
#################################################################
|
||||
# play(self)
|
||||
# It works pretty much like what we have in the Animation Panel.
|
||||
# The only different now is that we set two "pose" here.
|
||||
# When you do the blending animation by setPose, you don't have
|
||||
# to set them simultaneously.
|
||||
#################################################################
|
||||
self.animNameA = self.AnimEntryA.get()
|
||||
self.animNameB = self.AnimEntryB.get()
|
||||
if (self.animNameA in self['animList'])and(self.animNameB in self['animList']):
|
||||
self.playButton.config(state=DISABLED)
|
||||
self.lastT = globalClock.getFrameTime()
|
||||
taskMgr.add(self.playTask, self.id + '_UpdateTask')
|
||||
self.stopButton.config(state=NORMAL)
|
||||
else:
|
||||
print '----Illegal Animaion name!!', self.animNameA + ', '+ self.animNameB
|
||||
return
|
||||
|
||||
def playTask(self, task):
|
||||
#################################################################
|
||||
# playTask(self, task)
|
||||
# see play(self)
|
||||
#################################################################
|
||||
fLoop = self.loopVar.get()
|
||||
currT = globalClock.getFrameTime()
|
||||
deltaT = currT - self.lastT
|
||||
self.lastT = currT
|
||||
if self.dragMode:
|
||||
return Task.cont
|
||||
self.currTime = self.currTime + deltaT
|
||||
if (self.currTime > self.maxSeconds):
|
||||
if fLoop:
|
||||
self.currTime = self.currTime%self.duration
|
||||
self.gotoT(self.currTime)
|
||||
else:
|
||||
self.currTime = 0.0
|
||||
self.gotoT(0.0)
|
||||
self.playButton.config(state=NORMAL)
|
||||
self.stopButton.config(state=DISABLED)
|
||||
return Task.done
|
||||
else:
|
||||
self.gotoT(self.currTime)
|
||||
return Task.cont
|
||||
|
||||
def stop(self):
|
||||
#################################################################
|
||||
# stop(self)
|
||||
# see play(self)
|
||||
#################################################################
|
||||
taskMgr.remove(self.id + '_UpdateTask')
|
||||
self.playButton.config(state=NORMAL)
|
||||
self.stopButton.config(state=DISABLED)
|
||||
return
|
||||
|
||||
def setAnimation(self, animation, AB = 'a'):
|
||||
#################################################################
|
||||
# setAnimation(self, animation, AB = 'a')
|
||||
# see play(self)
|
||||
#################################################################
|
||||
print 'OK!!!'
|
||||
if AB == 'a':
|
||||
if self.animNameA != None:
|
||||
self['actor'].setControlEffect(self.animNameA, 1.0, 'modelRoot','lodRoot')
|
||||
self.animNameA = self.AnimEntryA.get()
|
||||
else:
|
||||
if self.animNameB != None:
|
||||
self['actor'].setControlEffect(self.animNameB, 1.0, 'modelRoot','lodRoot')
|
||||
self.animNameB = self.AnimEntryB.get()
|
||||
self.currTime = 0.0
|
||||
self.frameControl.set(0)
|
||||
self.updateDisplay()
|
||||
self.setRatio(self.blendRatio)
|
||||
return
|
||||
|
||||
def setPlayRate(self,rate):
|
||||
#################################################################
|
||||
# setPlayRate(self,rate)
|
||||
# see play(self)
|
||||
#################################################################
|
||||
self.animNameA = self.AnimEntryA.get()
|
||||
if self.animNameA in self['animList']:
|
||||
self['actor'].setPlayRate(eval(rate), self.animNameA)
|
||||
self.updateDisplay()
|
||||
if self.animNameB in self['animList']:
|
||||
self['actor'].setPlayRate(eval(rate), self.animNameB)
|
||||
self.updateDisplay()
|
||||
return
|
||||
|
||||
def updateDisplay(self):
|
||||
#################################################################
|
||||
# updateDisplay(self)
|
||||
# see play(self)
|
||||
#################################################################
|
||||
if not (self.animNameA in self['animList']):
|
||||
return
|
||||
self.fps = self['actor'].getFrameRate(self.animNameA)
|
||||
self.duration = self['actor'].getDuration(self.animNameA)
|
||||
self.maxFrame = self['actor'].getNumFrames(self.animNameA) - 1
|
||||
if not (self.animNameB in self['animList']):
|
||||
return
|
||||
if self.duration > self['actor'].getDuration(self.animNameB):
|
||||
self.duration = self['actor'].getDuration(self.animNameB)
|
||||
if self.maxFrame > self['actor'].getNumFrames(self.animNameB) - 1:
|
||||
self.maxFrame = self['actor'].getNumFrames(self.animNameB) - 1
|
||||
self.maxSeconds = self.duration
|
||||
if self.unitsVar.get() == FRAMES:
|
||||
fromFrame = 0
|
||||
toFrame = self.maxFrame
|
||||
self.minLabel['text'] = fromFrame
|
||||
self.maxLabel['text'] = toFrame
|
||||
self.frameControl.configure(from_ = fromFrame,
|
||||
to = toFrame,
|
||||
resolution = 1.0)
|
||||
else:
|
||||
self.minLabel['text'] = '0.0'
|
||||
self.maxLabel['text'] = "%.2f" % self.duration
|
||||
self.frameControl.configure(from_ = 0.0,
|
||||
to = self.duration,
|
||||
resolution = 0.01)
|
||||
|
||||
def gotoT(self,time):
|
||||
#################################################################
|
||||
# gotoT(self,time)
|
||||
# see play(self)
|
||||
#################################################################
|
||||
if self.unitsVar.get() == FRAMES:
|
||||
self.frameControl.set(time * self.fps)
|
||||
else:
|
||||
self.frameControl.set(time)
|
||||
return
|
||||
|
||||
def goTo(self,frame):
|
||||
#################################################################
|
||||
# goTo(self,frame)
|
||||
# see play(self)
|
||||
#################################################################
|
||||
if (self.animNameA in self['animList'])and(self.animNameB in self['animList']):
|
||||
# Convert scale value to float
|
||||
frame = string.atof(frame)
|
||||
# Now convert t to seconds for offset calculations
|
||||
if self.unitsVar.get() == FRAMES:
|
||||
frame = frame / self.fps
|
||||
if self.dragMode:
|
||||
self.currTime = frame
|
||||
self['actor'].pose(self.animNameA,
|
||||
min(self.maxFrame, int(frame * self.fps)))
|
||||
self['actor'].pose(self.animNameB,
|
||||
min(self.maxFrame, int(frame * self.fps)))
|
||||
return
|
||||
|
||||
def onRelease(self,frame):
|
||||
#################################################################
|
||||
# onRelease(self,frame)
|
||||
# see play(self)
|
||||
#################################################################
|
||||
self.dragMode = False
|
||||
return
|
||||
|
||||
def onPress(self,frame):
|
||||
#################################################################
|
||||
# onPress(self,frame)
|
||||
# see play(self)
|
||||
#################################################################
|
||||
self.dragMode = True
|
||||
return
|
||||
|
||||
def resetAllToZero(self):
|
||||
#################################################################
|
||||
# resetAllToZero(self)
|
||||
# see play(self)
|
||||
#################################################################
|
||||
self.currTime = 0.0
|
||||
self.gotoT(0)
|
||||
return
|
||||
|
||||
def resetAllToEnd(self):
|
||||
#################################################################
|
||||
# resetAllToEnd(self)
|
||||
# see play(self)
|
||||
#################################################################
|
||||
self.currTime = self.maxSeconds
|
||||
self.gotoT(self.duration)
|
||||
return
|
||||
|
||||
def toggleBlend(self):
|
||||
#################################################################
|
||||
# toggleBlend(self)
|
||||
# This function will enable the blending option for the actor.
|
||||
# and call set ratio function to set the blending animation mixing in
|
||||
# current ratio.
|
||||
#
|
||||
# This blending enable will not be keep when you close the window!
|
||||
#
|
||||
#################################################################
|
||||
if self.blendVar.get():
|
||||
self.enableBlend = True
|
||||
self['actor'].enableBlend()
|
||||
self.setRatio(self.blendRatio)
|
||||
else:
|
||||
self.enableBlend = False
|
||||
self['actor'].disableBlend()
|
||||
return
|
||||
|
||||
def setRatio(self, ratio):
|
||||
#################################################################
|
||||
# setRatio(self, ratio)
|
||||
# callback funtion
|
||||
# This one will be called each time when user drag the blend ratio
|
||||
# slider on the panel. This will set the blening ratio to both animation.
|
||||
# (Which is "setControlEffect")
|
||||
#################################################################
|
||||
self.blendRatio = float(ratio)
|
||||
if self.enableBlend:
|
||||
if self.animNameA in self['animList']:
|
||||
self['actor'].setControlEffect(self.animNameA, self.blendRatio, 'modelRoot','lodRoot')
|
||||
if self.animNameB in self['animList']:
|
||||
self['actor'].setControlEffect(self.animNameB, 1-self.blendRatio, 'modelRoot','lodRoot')
|
||||
return
|
||||
|
||||
def setBlendAnim(self, name):
|
||||
#################################################################
|
||||
# setBlendAnim(self, name)
|
||||
# This function will be called each time when user try to select
|
||||
# a existing blending animation from the comboBox on the panel
|
||||
# This function will re-set every varaibles on the panel to what
|
||||
# it should be. For example, when user choose blending anim "R,"
|
||||
# which was blended by anim "a" and "b" with ratio "c,"
|
||||
# then this function will set Animation A to "a" and animation B
|
||||
# to "b" and set the ratio slider to "c" position.
|
||||
#################################################################
|
||||
if self.blendDict.has_key(name):
|
||||
self.currentBlendName = name
|
||||
animA = self.blendDict[name][0]
|
||||
animB = self.blendDict[name][1]
|
||||
ratio = self.blendDict[name][2]
|
||||
self.AnimEntryA.selectitem(animA)
|
||||
self.AnimEntryB.selectitem(animB)
|
||||
self.setAnimation(animA, AB = 'a')
|
||||
self.setAnimation(animB, AB = 'b')
|
||||
self.ratioControl.set(ratio)
|
||||
return
|
||||
|
||||
def setBlendAnimList(self, dict, select=False):
|
||||
#################################################################
|
||||
# setBlendAnimList(self, dict, select=False)
|
||||
# This function will be called when we need to reset the dropdown list
|
||||
# of "Blend Anim."
|
||||
# About "selec" option, this now is mainly used when we remove
|
||||
# a blended animation from the actor. When it has been specified to True,
|
||||
# the function will not only reset the list, but will also automatically
|
||||
# select one from the top of list, if it is not empty.
|
||||
#################################################################
|
||||
self.blendDict.clear()
|
||||
del self.blendDict
|
||||
self.blendDict = dict.copy()
|
||||
print self.blendDict
|
||||
if len(self.blendDict)>0:
|
||||
self.blendList = self.blendDict.keys()
|
||||
else:
|
||||
self.blendList = []
|
||||
self.blendAnimEntry.setlist(self.blendList)
|
||||
if select:
|
||||
if len(self.blendList)>0:
|
||||
self.blendAnimEntry.selectitem(self.blendList[0])
|
||||
self.setBlendAnim(self.blendList[0])
|
||||
self.currentBlendName = self.blendList[0]
|
||||
else:
|
||||
self.blendAnimEntry.clear()
|
||||
self.currentBlendName = None
|
||||
return
|
||||
|
||||
def saveButtonPushed(self):
|
||||
#################################################################
|
||||
# saveButtonPushed(self)
|
||||
# This function will be called when user clicked on the "Save" button
|
||||
# This functiont will collect all data on the panel and send them with
|
||||
# a message to sceneEditor to save the current blending animation
|
||||
# into the dataHolder.
|
||||
#################################################################
|
||||
name = self.blendAnimEntry.get()
|
||||
if name=='':
|
||||
Pmw.MessageDialog(None, title='Caution!',
|
||||
message_text = 'You have to give the blending animation a name first!',
|
||||
iconpos='s',
|
||||
defaultbutton = 'Close'
|
||||
)
|
||||
return
|
||||
elif (not(self.animNameA in self['animList']))or(not(self.animNameB in self['animList'])):
|
||||
Pmw.MessageDialog(None, title='Caution!',
|
||||
message_text = 'The Animations you have selected are not exist!',
|
||||
iconpos='s',
|
||||
defaultbutton = 'Close'
|
||||
)
|
||||
return
|
||||
else:
|
||||
messenger.send('BAW_saveBlendAnim', [self['actor'].getName(),
|
||||
name,
|
||||
self.animNameA,
|
||||
self.animNameB,
|
||||
self.blendRatio])
|
||||
self.currentBlendName = name
|
||||
return
|
||||
|
||||
def removeButtonPushed(self):
|
||||
#################################################################
|
||||
# removeButtonPushed(self)
|
||||
# remove the current seleted blended animation from the actor.
|
||||
# This will send out a message to sceneEditor to delete the data inside
|
||||
# the dataHolder and then reset the list of here.
|
||||
#################################################################
|
||||
name = self.blendAnimEntry.get()
|
||||
messenger.send('BAW_removeBlendAnim', [self['actor'].getName(),name])
|
||||
return
|
||||
|
||||
def renameButtonPushed(self):
|
||||
#################################################################
|
||||
# renameButtonPushed(self)
|
||||
# this function will be called when user click on the "Rename" button.
|
||||
# This function will collect all data on the panel and send them out
|
||||
# with a message to sceneEditor to rename and re-save all setting about
|
||||
# current animation.
|
||||
#################################################################
|
||||
oName = self.currentBlendName
|
||||
name = self.blendAnimEntry.get()
|
||||
if self.currentBlendName == None:
|
||||
Pmw.MessageDialog(None, title='Caution!',
|
||||
message_text = "You haven't select any blended animation!!",
|
||||
iconpos='s',
|
||||
defaultbutton = 'Close'
|
||||
)
|
||||
return
|
||||
elif name=='':
|
||||
Pmw.MessageDialog(None, title='Caution!',
|
||||
message_text = 'You have to give the blending animation a name first!',
|
||||
iconpos='s',
|
||||
defaultbutton = 'Close'
|
||||
)
|
||||
return
|
||||
elif (not(self.animNameA in self['animList']))or(not(self.animNameB in self['animList'])):
|
||||
Pmw.MessageDialog(None, title='Caution!',
|
||||
message_text = 'The Animations you have selected are not exist!',
|
||||
iconpos='s',
|
||||
defaultbutton = 'Close'
|
||||
)
|
||||
return
|
||||
else:
|
||||
messenger.send('BAW_renameBlendAnim', [self['actor'].getName(),
|
||||
name,
|
||||
oName,
|
||||
self.animNameA,
|
||||
self.animNameB,
|
||||
self.blendRatio]
|
||||
)
|
||||
self.currentBlendName = name
|
||||
return
|
||||
|
||||
def onDestroy(self, event):
|
||||
#################################################################
|
||||
# onDestroy(self, event)
|
||||
# This function will be call when user try to close the window.
|
||||
# In here we will stop all tasks we have opend and disable the
|
||||
# blend setting of actor.
|
||||
# If we didn't disable the blend option, the next time you play
|
||||
# the animation via animation panel will cause some error.
|
||||
#################################################################
|
||||
if taskMgr.hasTaskNamed(self.id + '_UpdateTask'):
|
||||
taskMgr.remove(self.id + '_UpdateTask')
|
||||
messenger.send('BAW_close',[self.nodeName])
|
||||
self.actorNode.setControlEffect(self.animNameA, 1.0, 'modelRoot','lodRoot')
|
||||
self.actorNode.setControlEffect(self.animNameB, 1.0, 'modelRoot','lodRoot')
|
||||
self.actorNode.disableBlend()
|
||||
'''
|
||||
If you have open any thing, please rewrite here!
|
||||
'''
|
||||
pass
|
670
build/nirai/panda3d/contrib/src/sceneeditor/seCameraControl.py
Normal file
670
build/nirai/panda3d/contrib/src/sceneeditor/seCameraControl.py
Normal file
|
@ -0,0 +1,670 @@
|
|||
#################################################################
|
||||
# seCameraControl.py
|
||||
# Originally from DirectCameraControl.py
|
||||
# Altered by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#
|
||||
# We didn't change anything essential.
|
||||
# Just because we customized the seSession from DirectSession,
|
||||
# So we need related files can follow the change.
|
||||
# However, we don't want to change anything inside the original directool
|
||||
# to let them can work with our scene editor.
|
||||
# (If we do change original directools, it will force user has to install the latest version of OUR Panda)
|
||||
#
|
||||
#################################################################
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from direct.directtools.DirectUtil import *
|
||||
from seGeometry import *
|
||||
from direct.directtools.DirectGlobals import *
|
||||
from direct.task import Task
|
||||
|
||||
CAM_MOVE_DURATION = 1.2
|
||||
COA_MARKER_SF = 0.0075
|
||||
Y_AXIS = Vec3(0,1,0)
|
||||
|
||||
class DirectCameraControl(DirectObject):
|
||||
def __init__(self):
|
||||
# Create the grid
|
||||
self.startT = 0.0
|
||||
self.startF = 0
|
||||
self.orthoViewRoll = 0.0
|
||||
self.lastView = 0
|
||||
self.coa = Point3(0,100,0)
|
||||
self.coaMarker = loader.loadModel('models/misc/sphere')
|
||||
self.coaMarker.setName('DirectCameraCOAMarker')
|
||||
self.coaMarker.setTransparency(1)
|
||||
self.coaMarker.setColor(1,0,0,0)
|
||||
self.coaMarker.setPos(0,100,0)
|
||||
useDirectRenderStyle(self.coaMarker)
|
||||
self.coaMarkerPos = Point3(0)
|
||||
self.fLockCOA = 0
|
||||
self.nullHitPointCount = 0
|
||||
self.cqEntries = []
|
||||
self.coaMarkerRef = SEditor.group.attachNewNode('coaMarkerRef')
|
||||
self.camManipRef = SEditor.group.attachNewNode('camManipRef')
|
||||
t = CAM_MOVE_DURATION
|
||||
self.actionEvents = [
|
||||
['DIRECT-mouse2', self.mouseFlyStart],
|
||||
['DIRECT-mouse2Up', self.mouseFlyStop],
|
||||
]
|
||||
self.keyEvents = [
|
||||
['c', self.centerCamIn, 0.5],
|
||||
['f', self.fitOnWidget],
|
||||
['h', self.homeCam],
|
||||
['shift-v', self.toggleMarkerVis],
|
||||
['m', self.moveToFit],
|
||||
['n', self.pickNextCOA],
|
||||
['u', self.orbitUprightCam],
|
||||
['shift-u', self.uprightCam],
|
||||
[`1`, self.spawnMoveToView, 1],
|
||||
[`2`, self.spawnMoveToView, 2],
|
||||
[`3`, self.spawnMoveToView, 3],
|
||||
[`4`, self.spawnMoveToView, 4],
|
||||
[`5`, self.spawnMoveToView, 5],
|
||||
[`6`, self.spawnMoveToView, 6],
|
||||
[`7`, self.spawnMoveToView, 7],
|
||||
[`8`, self.spawnMoveToView, 8],
|
||||
['9', self.swingCamAboutWidget, -90.0, t],
|
||||
['0', self.swingCamAboutWidget, 90.0, t],
|
||||
['`', self.removeManipulateCameraTask],
|
||||
['=', self.zoomCam, 0.5, t],
|
||||
['+', self.zoomCam, 0.5, t],
|
||||
['-', self.zoomCam, -2.0, t],
|
||||
['_', self.zoomCam, -2.0, t],
|
||||
]
|
||||
|
||||
def toggleMarkerVis(self):
|
||||
if SEditor.cameraControl.coaMarker.isHidden():
|
||||
SEditor.cameraControl.coaMarker.show()
|
||||
else:
|
||||
SEditor.cameraControl.coaMarker.hide()
|
||||
|
||||
def mouseFlyStart(self, modifiers):
|
||||
# Record undo point
|
||||
SEditor.pushUndo([SEditor.camera])
|
||||
# Where are we in the display region?
|
||||
if ((abs(SEditor.dr.mouseX) < 0.9) and (abs(SEditor.dr.mouseY) < 0.9)):
|
||||
# MOUSE IS IN CENTRAL REGION
|
||||
# Hide the marker for this kind of motion
|
||||
self.coaMarker.hide()
|
||||
# Record time of start of mouse interaction
|
||||
self.startT= globalClock.getFrameTime()
|
||||
self.startF = globalClock.getFrameCount()
|
||||
# Start manipulation
|
||||
self.spawnXZTranslateOrHPanYZoom()
|
||||
# END MOUSE IN CENTRAL REGION
|
||||
else:
|
||||
if ((abs(SEditor.dr.mouseX) > 0.9) and
|
||||
(abs(SEditor.dr.mouseY) > 0.9)):
|
||||
# Mouse is in corners, spawn roll task
|
||||
self.spawnMouseRollTask()
|
||||
else:
|
||||
# Mouse is in outer frame, spawn mouseRotateTask
|
||||
self.spawnMouseRotateTask()
|
||||
|
||||
def mouseFlyStop(self):
|
||||
taskMgr.remove('manipulateCamera')
|
||||
stopT = globalClock.getFrameTime()
|
||||
deltaT = stopT - self.startT
|
||||
stopF = globalClock.getFrameCount()
|
||||
deltaF = stopF - self.startF
|
||||
if (deltaT <= 0.25) or (deltaF <= 1):
|
||||
# Check for a hit point based on
|
||||
# current mouse position
|
||||
# Allow intersection with unpickable objects
|
||||
# And then spawn task to determine mouse mode
|
||||
# Don't intersect with hidden or backfacing objects
|
||||
skipFlags = SKIP_HIDDEN | SKIP_BACKFACE
|
||||
# Skip camera (and its children), unless control key is pressed
|
||||
skipFlags |= SKIP_CAMERA * (1 - base.getControl())
|
||||
self.computeCOA(SEditor.iRay.pickGeom(skipFlags = skipFlags))
|
||||
# Record reference point
|
||||
self.coaMarkerRef.iPosHprScale(base.cam)
|
||||
# Record entries
|
||||
self.cqEntries = []
|
||||
for i in range(SEditor.iRay.getNumEntries()):
|
||||
self.cqEntries.append(SEditor.iRay.getEntry(i))
|
||||
# Show the marker
|
||||
self.coaMarker.show()
|
||||
# Resize it
|
||||
self.updateCoaMarkerSize()
|
||||
|
||||
def spawnXZTranslateOrHPanYZoom(self):
|
||||
# Kill any existing tasks
|
||||
taskMgr.remove('manipulateCamera')
|
||||
# Spawn the new task
|
||||
t = Task.Task(self.XZTranslateOrHPanYZoomTask)
|
||||
# For HPanYZoom
|
||||
t.zoomSF = Vec3(self.coaMarker.getPos(SEditor.camera)).length()
|
||||
taskMgr.add(t, 'manipulateCamera')
|
||||
|
||||
def spawnXZTranslateOrHPPan(self):
|
||||
# Kill any existing tasks
|
||||
taskMgr.remove('manipulateCamera')
|
||||
# Spawn new task
|
||||
taskMgr.add(self.XZTranslateOrHPPanTask,
|
||||
'manipulateCamera')
|
||||
|
||||
def spawnXZTranslate(self):
|
||||
# Kill any existing tasks
|
||||
taskMgr.remove('manipulateCamera')
|
||||
# Spawn new task
|
||||
taskMgr.add(self.XZTranslateTask, 'manipulateCamera')
|
||||
|
||||
def spawnHPanYZoom(self):
|
||||
# Kill any existing tasks
|
||||
taskMgr.remove('manipulateCamera')
|
||||
# Spawn new task
|
||||
t = Task.Task(self.HPanYZoomTask)
|
||||
t.zoomSF = Vec3(self.coaMarker.getPos(SEditor.camera)).length()
|
||||
taskMgr.add(t, 'manipulateCamera')
|
||||
|
||||
def spawnHPPan(self):
|
||||
# Kill any existing tasks
|
||||
taskMgr.remove('manipulateCamera')
|
||||
# Spawn new task
|
||||
taskMgr.add(self.HPPanTask, 'manipulateCamera')
|
||||
|
||||
def XZTranslateOrHPanYZoomTask(self, state):
|
||||
if SEditor.fShift:
|
||||
return self.XZTranslateTask(state)
|
||||
else:
|
||||
return self.HPanYZoomTask(state)
|
||||
|
||||
def XZTranslateOrHPPanTask(self, state):
|
||||
if SEditor.fShift:
|
||||
# Panning action
|
||||
return self.HPPanTask(state)
|
||||
else:
|
||||
# Translation action
|
||||
return self.XZTranslateTask(state)
|
||||
|
||||
def XZTranslateTask(self,state):
|
||||
coaDist = Vec3(self.coaMarker.getPos(SEditor.camera)).length()
|
||||
xlateSF = (coaDist / SEditor.dr.near)
|
||||
SEditor.camera.setPos(SEditor.camera,
|
||||
(-0.5 * SEditor.dr.mouseDeltaX *
|
||||
SEditor.dr.nearWidth *
|
||||
xlateSF),
|
||||
0.0,
|
||||
(-0.5 * SEditor.dr.mouseDeltaY *
|
||||
SEditor.dr.nearHeight *
|
||||
xlateSF))
|
||||
return Task.cont
|
||||
|
||||
def HPanYZoomTask(self,state):
|
||||
if SEditor.fControl:
|
||||
moveDir = Vec3(self.coaMarker.getPos(SEditor.camera))
|
||||
# If marker is behind camera invert vector
|
||||
if moveDir[1] < 0.0:
|
||||
moveDir.assign(moveDir * -1)
|
||||
moveDir.normalize()
|
||||
else:
|
||||
moveDir = Vec3(Y_AXIS)
|
||||
moveDir.assign(moveDir * (-1.0 * SEditor.dr.mouseDeltaY *
|
||||
state.zoomSF))
|
||||
if SEditor.dr.mouseDeltaY > 0.0:
|
||||
moveDir.setY(moveDir[1] * 1.0)
|
||||
SEditor.camera.setPosHpr(SEditor.camera,
|
||||
moveDir[0],
|
||||
moveDir[1],
|
||||
moveDir[2],
|
||||
(0.5 * SEditor.dr.mouseDeltaX *
|
||||
SEditor.dr.fovH),
|
||||
0.0, 0.0)
|
||||
return Task.cont
|
||||
|
||||
def HPPanTask(self, state):
|
||||
SEditor.camera.setHpr(SEditor.camera,
|
||||
(0.5 * SEditor.dr.mouseDeltaX *
|
||||
SEditor.dr.fovH),
|
||||
(-0.5 * SEditor.dr.mouseDeltaY *
|
||||
SEditor.dr.fovV),
|
||||
0.0)
|
||||
return Task.cont
|
||||
|
||||
def spawnMouseRotateTask(self):
|
||||
# Kill any existing tasks
|
||||
taskMgr.remove('manipulateCamera')
|
||||
# Set at markers position in render coordinates
|
||||
self.camManipRef.setPos(self.coaMarkerPos)
|
||||
self.camManipRef.setHpr(SEditor.camera, ZERO_POINT)
|
||||
t = Task.Task(self.mouseRotateTask)
|
||||
if abs(SEditor.dr.mouseX) > 0.9:
|
||||
t.constrainedDir = 'y'
|
||||
else:
|
||||
t.constrainedDir = 'x'
|
||||
taskMgr.add(t, 'manipulateCamera')
|
||||
|
||||
def mouseRotateTask(self, state):
|
||||
# If moving outside of center, ignore motion perpendicular to edge
|
||||
if ((state.constrainedDir == 'y') and (abs(SEditor.dr.mouseX) > 0.9)):
|
||||
deltaX = 0
|
||||
deltaY = SEditor.dr.mouseDeltaY
|
||||
elif ((state.constrainedDir == 'x') and (abs(SEditor.dr.mouseY) > 0.9)):
|
||||
deltaX = SEditor.dr.mouseDeltaX
|
||||
deltaY = 0
|
||||
else:
|
||||
deltaX = SEditor.dr.mouseDeltaX
|
||||
deltaY = SEditor.dr.mouseDeltaY
|
||||
if SEditor.fShift:
|
||||
SEditor.camera.setHpr(SEditor.camera,
|
||||
(deltaX * SEditor.dr.fovH),
|
||||
(-deltaY * SEditor.dr.fovV),
|
||||
0.0)
|
||||
self.camManipRef.setPos(self.coaMarkerPos)
|
||||
self.camManipRef.setHpr(SEditor.camera, ZERO_POINT)
|
||||
else:
|
||||
wrt = SEditor.camera.getTransform( self.camManipRef )
|
||||
self.camManipRef.setHpr(self.camManipRef,
|
||||
(-1 * deltaX * 180.0),
|
||||
(deltaY * 180.0),
|
||||
0.0)
|
||||
SEditor.camera.setTransform(self.camManipRef, wrt)
|
||||
return Task.cont
|
||||
|
||||
def spawnMouseRollTask(self):
|
||||
# Kill any existing tasks
|
||||
taskMgr.remove('manipulateCamera')
|
||||
# Set at markers position in render coordinates
|
||||
self.camManipRef.setPos(self.coaMarkerPos)
|
||||
self.camManipRef.setHpr(SEditor.camera, ZERO_POINT)
|
||||
t = Task.Task(self.mouseRollTask)
|
||||
t.coaCenter = getScreenXY(self.coaMarker)
|
||||
t.lastAngle = getCrankAngle(t.coaCenter)
|
||||
# Store the camera/manipRef offset transform
|
||||
t.wrt = SEditor.camera.getTransform( self.camManipRef )
|
||||
taskMgr.add(t, 'manipulateCamera')
|
||||
|
||||
def mouseRollTask(self, state):
|
||||
wrt = state.wrt
|
||||
angle = getCrankAngle(state.coaCenter)
|
||||
deltaAngle = angle - state.lastAngle
|
||||
state.lastAngle = angle
|
||||
if base.config.GetBool('temp-hpr-fix',0):
|
||||
self.camManipRef.setHpr(self.camManipRef, 0, 0, deltaAngle)
|
||||
else:
|
||||
self.camManipRef.setHpr(self.camManipRef, 0, 0, -deltaAngle)
|
||||
SEditor.camera.setTransform(self.camManipRef, wrt)
|
||||
return Task.cont
|
||||
|
||||
def lockCOA(self):
|
||||
self.fLockCOA = 1
|
||||
SEditor.message('COA Lock On')
|
||||
|
||||
def unlockCOA(self):
|
||||
self.fLockCOA = 0
|
||||
SEditor.message('COA Lock Off')
|
||||
|
||||
def toggleCOALock(self):
|
||||
self.fLockCOA = 1 - self.fLockCOA
|
||||
if self.fLockCOA:
|
||||
SEditor.message('COA Lock On')
|
||||
else:
|
||||
SEditor.message('COA Lock Off')
|
||||
|
||||
def pickNextCOA(self):
|
||||
""" Cycle through collision handler entries """
|
||||
if self.cqEntries:
|
||||
# Get next entry and rotate entries
|
||||
entry = self.cqEntries[0]
|
||||
self.cqEntries = self.cqEntries[1:] + self.cqEntries[:1]
|
||||
# Filter out object's under camera
|
||||
nodePath = entry.getIntoNodePath()
|
||||
if SEditor.camera not in nodePath.getAncestors():
|
||||
# Compute new hit point
|
||||
hitPt = entry.getSurfacePoint(entry.getFromNodePath())
|
||||
# Move coa marker to new point
|
||||
self.updateCoa(hitPt, ref = self.coaMarkerRef)
|
||||
else:
|
||||
# Remove offending entry
|
||||
self.cqEntries = self.cqEntries[:-1]
|
||||
self.pickNextCOA()
|
||||
|
||||
def computeCOA(self, entry):
|
||||
coa = Point3(0)
|
||||
dr = SEditor.drList.getCurrentDr()
|
||||
if self.fLockCOA:
|
||||
# COA is locked, use existing point
|
||||
# Use existing point
|
||||
coa.assign(self.coaMarker.getPos(SEditor.camera))
|
||||
# Reset hit point count
|
||||
self.nullHitPointCount = 0
|
||||
elif entry:
|
||||
# Got a hit point (hit point is in camera coordinates)
|
||||
# Set center of action
|
||||
hitPt = entry.getSurfacePoint(entry.getFromNodePath())
|
||||
hitPtDist = Vec3(hitPt).length()
|
||||
coa.assign(hitPt)
|
||||
# Handle case of bad coa point (too close or too far)
|
||||
if ((hitPtDist < (1.1 * dr.near)) or
|
||||
(hitPtDist > dr.far)):
|
||||
# Just use existing point
|
||||
coa.assign(self.coaMarker.getPos(SEditor.camera))
|
||||
# Reset hit point count
|
||||
self.nullHitPointCount = 0
|
||||
else:
|
||||
# Increment null hit point count
|
||||
self.nullHitPointCount = (self.nullHitPointCount + 1) % 7
|
||||
# No COA lock and no intersection point
|
||||
# Use a point out in front of camera
|
||||
# Distance to point increases on multiple null hit points
|
||||
# MRM: Would be nice to be able to control this
|
||||
# At least display it
|
||||
dist = pow(10.0, self.nullHitPointCount)
|
||||
SEditor.message('COA Distance: ' + `dist`)
|
||||
coa.set(0,dist,0)
|
||||
# Compute COA Dist
|
||||
coaDist = Vec3(coa - ZERO_POINT).length()
|
||||
if coaDist < (1.1 * dr.near):
|
||||
coa.set(0,100,0)
|
||||
coaDist = 100
|
||||
# Update coa and marker
|
||||
self.updateCoa(coa, coaDist = coaDist)
|
||||
|
||||
def updateCoa(self, ref2point, coaDist = None, ref = None):
|
||||
self.coa.set(ref2point[0], ref2point[1], ref2point[2])
|
||||
if not coaDist:
|
||||
coaDist = Vec3(self.coa - ZERO_POINT).length()
|
||||
# Place the marker in render space
|
||||
if ref == None:
|
||||
# KEH: use the current display region
|
||||
# ref = base.cam
|
||||
ref = SEditor.drList.getCurrentDr().cam
|
||||
self.coaMarker.setPos(ref, self.coa)
|
||||
pos = self.coaMarker.getPos()
|
||||
self.coaMarker.setPosHprScale(pos, Vec3(0), Vec3(1))
|
||||
# Resize it
|
||||
self.updateCoaMarkerSize(coaDist)
|
||||
# Record marker pos in render space
|
||||
self.coaMarkerPos.assign(self.coaMarker.getPos())
|
||||
|
||||
def updateCoaMarkerSizeOnDeath(self, state):
|
||||
# Needed because tasks pass in state as first arg
|
||||
self.updateCoaMarkerSize()
|
||||
|
||||
def updateCoaMarkerSize(self, coaDist = None):
|
||||
if not coaDist:
|
||||
coaDist = Vec3(self.coaMarker.getPos( SEditor.camera )).length()
|
||||
# KEH: use current display region for fov
|
||||
# sf = COA_MARKER_SF * coaDist * math.tan(deg2Rad(SEditor.dr.fovV))
|
||||
sf = COA_MARKER_SF * coaDist * math.tan(deg2Rad(SEditor.drList.getCurrentDr().fovV))
|
||||
if sf == 0.0:
|
||||
sf = 0.1
|
||||
self.coaMarker.setScale(sf)
|
||||
# Lerp color to fade out
|
||||
self.coaMarker.lerpColor(VBase4(1,0,0,1), VBase4(1,0,0,0), 3.0,
|
||||
task = 'fadeAway')
|
||||
|
||||
def homeCam(self):
|
||||
# Record undo point
|
||||
SEditor.pushUndo([SEditor.camera])
|
||||
SEditor.camera.reparentTo(render)
|
||||
SEditor.camera.clearMat()
|
||||
# Resize coa marker
|
||||
self.updateCoaMarkerSize()
|
||||
|
||||
def uprightCam(self):
|
||||
taskMgr.remove('manipulateCamera')
|
||||
# Record undo point
|
||||
SEditor.pushUndo([SEditor.camera])
|
||||
# Pitch camera till upright
|
||||
currH = SEditor.camera.getH()
|
||||
SEditor.camera.lerpHpr(currH, 0, 0,
|
||||
CAM_MOVE_DURATION,
|
||||
other = render,
|
||||
blendType = 'easeInOut',
|
||||
task = 'manipulateCamera')
|
||||
|
||||
def orbitUprightCam(self):
|
||||
taskMgr.remove('manipulateCamera')
|
||||
# Record undo point
|
||||
SEditor.pushUndo([SEditor.camera])
|
||||
# Transform camera z axis to render space
|
||||
mCam2Render = Mat4()
|
||||
mCam2Render.assign(SEditor.camera.getMat(render))
|
||||
zAxis = Vec3(mCam2Render.xformVec(Z_AXIS))
|
||||
zAxis.normalize()
|
||||
# Compute rotation angle needed to upright cam
|
||||
orbitAngle = rad2Deg(math.acos(CLAMP(zAxis.dot(Z_AXIS),-1,1)))
|
||||
# Check angle
|
||||
if orbitAngle < 0.1:
|
||||
# Already upright
|
||||
return
|
||||
# Compute orthogonal axis of rotation
|
||||
rotAxis = Vec3(zAxis.cross(Z_AXIS))
|
||||
rotAxis.normalize()
|
||||
# Find angle between rot Axis and render X_AXIS
|
||||
rotAngle = rad2Deg(math.acos(CLAMP(rotAxis.dot(X_AXIS),-1,1)))
|
||||
# Determine sign or rotation angle
|
||||
if rotAxis[1] < 0:
|
||||
rotAngle *= -1
|
||||
# Position ref CS at coa marker with xaxis aligned with rot axis
|
||||
self.camManipRef.setPos(self.coaMarker, Vec3(0))
|
||||
self.camManipRef.setHpr(render, rotAngle, 0, 0)
|
||||
# Reparent Cam to ref Coordinate system
|
||||
parent = SEditor.camera.getParent()
|
||||
SEditor.camera.wrtReparentTo(self.camManipRef)
|
||||
# Rotate ref CS to final orientation
|
||||
t = self.camManipRef.lerpHpr(rotAngle, orbitAngle, 0,
|
||||
CAM_MOVE_DURATION,
|
||||
other = render,
|
||||
blendType = 'easeInOut',
|
||||
task = 'manipulateCamera')
|
||||
# Upon death, reparent Cam to parent
|
||||
t.parent = parent
|
||||
t.uponDeath = self.reparentCam
|
||||
|
||||
def centerCam(self):
|
||||
self.centerCamIn(1.0)
|
||||
|
||||
def centerCamNow(self):
|
||||
self.centerCamIn(0.)
|
||||
|
||||
def centerCamIn(self, t):
|
||||
taskMgr.remove('manipulateCamera')
|
||||
# Record undo point
|
||||
SEditor.pushUndo([SEditor.camera])
|
||||
# Determine marker location
|
||||
markerToCam = self.coaMarker.getPos( SEditor.camera )
|
||||
dist = Vec3(markerToCam - ZERO_POINT).length()
|
||||
scaledCenterVec = Y_AXIS * dist
|
||||
delta = markerToCam - scaledCenterVec
|
||||
self.camManipRef.setPosHpr(SEditor.camera, Point3(0), Point3(0))
|
||||
t = SEditor.camera.lerpPos(Point3(delta),
|
||||
CAM_MOVE_DURATION,
|
||||
other = self.camManipRef,
|
||||
blendType = 'easeInOut',
|
||||
task = 'manipulateCamera')
|
||||
t.uponDeath = self.updateCoaMarkerSizeOnDeath
|
||||
|
||||
def zoomCam(self, zoomFactor, t):
|
||||
taskMgr.remove('manipulateCamera')
|
||||
# Record undo point
|
||||
SEditor.pushUndo([SEditor.camera])
|
||||
# Find a point zoom factor times the current separation
|
||||
# of the widget and cam
|
||||
zoomPtToCam = self.coaMarker.getPos(SEditor.camera) * zoomFactor
|
||||
# Put a target nodePath there
|
||||
self.camManipRef.setPos(SEditor.camera, zoomPtToCam)
|
||||
# Move to that point
|
||||
t = SEditor.camera.lerpPos(ZERO_POINT,
|
||||
CAM_MOVE_DURATION,
|
||||
other = self.camManipRef,
|
||||
blendType = 'easeInOut',
|
||||
task = 'manipulateCamera')
|
||||
t.uponDeath = self.updateCoaMarkerSizeOnDeath
|
||||
|
||||
def spawnMoveToView(self, view):
|
||||
# Kill any existing tasks
|
||||
taskMgr.remove('manipulateCamera')
|
||||
# Record undo point
|
||||
SEditor.pushUndo([SEditor.camera])
|
||||
# Calc hprOffset
|
||||
hprOffset = VBase3()
|
||||
if view == 8:
|
||||
# Try the next roll angle
|
||||
self.orthoViewRoll = (self.orthoViewRoll + 90.0) % 360.0
|
||||
# but use the last view
|
||||
view = self.lastView
|
||||
else:
|
||||
self.orthoViewRoll = 0.0
|
||||
# Adjust offset based on specified view
|
||||
if view == 1:
|
||||
hprOffset.set(180., 0., 0.)
|
||||
elif view == 2:
|
||||
hprOffset.set(0., 0., 0.)
|
||||
elif view == 3:
|
||||
hprOffset.set(90., 0., 0.)
|
||||
elif view == 4:
|
||||
hprOffset.set(-90., 0., 0.)
|
||||
elif view == 5:
|
||||
hprOffset.set(0., -90., 0.)
|
||||
elif view == 6:
|
||||
hprOffset.set(0., 90., 0.)
|
||||
elif view == 7:
|
||||
hprOffset.set(135., -35.264, 0.)
|
||||
# Position target
|
||||
self.camManipRef.setPosHpr(self.coaMarker, ZERO_VEC,
|
||||
hprOffset)
|
||||
# Scale center vec by current distance to target
|
||||
offsetDistance = Vec3(SEditor.camera.getPos(self.camManipRef) -
|
||||
ZERO_POINT).length()
|
||||
scaledCenterVec = Y_AXIS * (-1.0 * offsetDistance)
|
||||
# Now put the camManipRef at that point
|
||||
self.camManipRef.setPosHpr(self.camManipRef,
|
||||
scaledCenterVec,
|
||||
ZERO_VEC)
|
||||
# Record view for next time around
|
||||
self.lastView = view
|
||||
t = SEditor.camera.lerpPosHpr(ZERO_POINT,
|
||||
VBase3(0,0,self.orthoViewRoll),
|
||||
CAM_MOVE_DURATION,
|
||||
other = self.camManipRef,
|
||||
blendType = 'easeInOut',
|
||||
task = 'manipulateCamera')
|
||||
t.uponDeath = self.updateCoaMarkerSizeOnDeath
|
||||
|
||||
|
||||
def swingCamAboutWidget(self, degrees, t):
|
||||
# Remove existing camera manipulation task
|
||||
taskMgr.remove('manipulateCamera')
|
||||
|
||||
# Record undo point
|
||||
SEditor.pushUndo([SEditor.camera])
|
||||
|
||||
# Coincident with widget
|
||||
self.camManipRef.setPos(self.coaMarker, ZERO_POINT)
|
||||
# But aligned with render space
|
||||
self.camManipRef.setHpr(ZERO_POINT)
|
||||
|
||||
parent = SEditor.camera.getParent()
|
||||
SEditor.camera.wrtReparentTo(self.camManipRef)
|
||||
|
||||
manipTask = self.camManipRef.lerpHpr(VBase3(degrees,0,0),
|
||||
CAM_MOVE_DURATION,
|
||||
blendType = 'easeInOut',
|
||||
task = 'manipulateCamera')
|
||||
# Upon death, reparent Cam to parent
|
||||
manipTask.parent = parent
|
||||
manipTask.uponDeath = self.reparentCam
|
||||
|
||||
def reparentCam(self, state):
|
||||
SEditor.camera.wrtReparentTo(state.parent)
|
||||
self.updateCoaMarkerSize()
|
||||
|
||||
def fitOnWidget(self, nodePath = 'None Given'):
|
||||
# Fit the node on the screen
|
||||
# stop any ongoing tasks
|
||||
taskMgr.remove('manipulateCamera')
|
||||
# How big is the node?
|
||||
nodeScale = SEditor.widget.scalingNode.getScale(render)
|
||||
maxScale = max(nodeScale[0],nodeScale[1],nodeScale[2])
|
||||
maxDim = min(SEditor.dr.nearWidth, SEditor.dr.nearHeight)
|
||||
|
||||
# At what distance does the object fill 30% of the screen?
|
||||
# Assuming radius of 1 on widget
|
||||
camY = SEditor.dr.near * (2.0 * maxScale)/(0.3 * maxDim)
|
||||
|
||||
# What is the vector through the center of the screen?
|
||||
centerVec = Y_AXIS * camY
|
||||
|
||||
# Where is the node relative to the viewpoint
|
||||
vWidget2Camera = SEditor.widget.getPos(SEditor.camera)
|
||||
|
||||
# How far do you move the camera to be this distance from the node?
|
||||
deltaMove = vWidget2Camera - centerVec
|
||||
|
||||
# Move a target there
|
||||
self.camManipRef.setPos(SEditor.camera, deltaMove)
|
||||
|
||||
parent = SEditor.camera.getParent()
|
||||
SEditor.camera.wrtReparentTo(self.camManipRef)
|
||||
fitTask = SEditor.camera.lerpPos(Point3(0,0,0),
|
||||
CAM_MOVE_DURATION,
|
||||
blendType = 'easeInOut',
|
||||
task = 'manipulateCamera')
|
||||
# Upon death, reparent Cam to parent
|
||||
fitTask.parent = parent
|
||||
fitTask.uponDeath = self.reparentCam
|
||||
|
||||
def moveToFit(self):
|
||||
# How bit is the active widget?
|
||||
widgetScale = SEditor.widget.scalingNode.getScale(render)
|
||||
maxScale = max(widgetScale[0], widgetScale[1], widgetScale[2])
|
||||
# At what distance does the widget fill 50% of the screen?
|
||||
camY = ((2 * SEditor.dr.near * (1.5 * maxScale)) /
|
||||
min(SEditor.dr.nearWidth, SEditor.dr.nearHeight))
|
||||
# Find a point this distance along the Y axis
|
||||
# MRM: This needs to be generalized to support non uniform frusta
|
||||
centerVec = Y_AXIS * camY
|
||||
# Before moving, record the relationship between the selected nodes
|
||||
# and the widget, so that this can be maintained
|
||||
SEditor.selected.getWrtAll()
|
||||
# Push state onto undo stack
|
||||
SEditor.pushUndo(SEditor.selected)
|
||||
# Remove the task to keep the widget attached to the object
|
||||
taskMgr.remove('followSelectedNodePath')
|
||||
# Spawn a task to keep the selected objects with the widget
|
||||
taskMgr.add(self.stickToWidgetTask, 'stickToWidget')
|
||||
# Spawn a task to move the widget
|
||||
t = SEditor.widget.lerpPos(Point3(centerVec),
|
||||
CAM_MOVE_DURATION,
|
||||
other = SEditor.camera,
|
||||
blendType = 'easeInOut',
|
||||
task = 'moveToFitTask')
|
||||
t.uponDeath = lambda state: taskMgr.remove('stickToWidget')
|
||||
|
||||
def stickToWidgetTask(self, state):
|
||||
# Move the objects with the widget
|
||||
SEditor.selected.moveWrtWidgetAll()
|
||||
# Continue
|
||||
return Task.cont
|
||||
|
||||
def enableMouseFly(self, fKeyEvents = 1):
|
||||
# disable C++ fly interface
|
||||
base.disableMouse()
|
||||
# Enable events
|
||||
for event in self.actionEvents:
|
||||
self.accept(event[0], event[1], extraArgs = event[2:])
|
||||
if fKeyEvents:
|
||||
for event in self.keyEvents:
|
||||
self.accept(event[0], event[1], extraArgs = event[2:])
|
||||
# Show marker
|
||||
self.coaMarker.reparentTo(SEditor.group)
|
||||
|
||||
def disableMouseFly(self):
|
||||
# Hide the marker
|
||||
self.coaMarker.reparentTo(hidden)
|
||||
# Ignore events
|
||||
for event in self.actionEvents:
|
||||
self.ignore(event[0])
|
||||
for event in self.keyEvents:
|
||||
self.ignore(event[0])
|
||||
# Kill tasks
|
||||
self.removeManipulateCameraTask()
|
||||
taskMgr.remove('stickToWidget')
|
||||
base.enableMouse()
|
||||
|
||||
def removeManipulateCameraTask(self):
|
||||
taskMgr.remove('manipulateCamera')
|
||||
|
49
build/nirai/panda3d/contrib/src/sceneeditor/seColorEntry.py
Normal file
49
build/nirai/panda3d/contrib/src/sceneeditor/seColorEntry.py
Normal file
|
@ -0,0 +1,49 @@
|
|||
#################################################################
|
||||
# seColorEntry.py
|
||||
# Originally from VectorWidgets.py
|
||||
# Altered by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#
|
||||
# Here we need some widget to handle some color input.
|
||||
# There is some colorEntry in the VectorWidgets.py, but they didn't
|
||||
# work as we need (we don't need alpha here. so the dim option should be set to 3).
|
||||
# So we make one from them.
|
||||
#
|
||||
#################################################################
|
||||
from direct.tkwidgets import Valuator
|
||||
from direct.tkwidgets import Floater
|
||||
from direct.tkwidgets import Slider
|
||||
import string, Pmw, Tkinter, tkColorChooser
|
||||
from direct.tkwidgets.VectorWidgets import VectorEntry
|
||||
|
||||
class seColorEntry(VectorEntry):
|
||||
def __init__(self, parent = None, **kw):
|
||||
# Initialize options for the class (overriding some superclass options)
|
||||
optiondefs = (
|
||||
('dim', 3, Pmw.INITOPT),
|
||||
('type', 'slider', Pmw.INITOPT),
|
||||
('fGroup_labels', ('R','G','B'), None),
|
||||
('min', 0.0, None),
|
||||
('max', 255.0, None),
|
||||
('nuDigits', 0, None),
|
||||
('valuator_resolution', 1.0, None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
# Initialize the superclass, make sure dim makes it to superclass
|
||||
VectorEntry.__init__(self, parent, dim = self['dim'])
|
||||
# Add menu item to popup color picker
|
||||
self.addMenuItem(
|
||||
'Popup color picker',
|
||||
command = lambda s = self: s.popupColorPicker())
|
||||
# Needed because this method checks if self.__class__ is myClass
|
||||
# where myClass is the argument passed into inialiseoptions
|
||||
self.initialiseoptions(seColorEntry)
|
||||
|
||||
def popupColorPicker(self):
|
||||
# Can pass in current color with: color = (255, 0, 0)
|
||||
color = tkColorChooser.askcolor(
|
||||
parent = self.interior(),
|
||||
# Initialize it to current color
|
||||
initialcolor = tuple(self.get()[:3]))[0]
|
||||
if color:
|
||||
self.set((color[0], color[1], color[2]))
|
915
build/nirai/panda3d/contrib/src/sceneeditor/seFileSaver.py
Normal file
915
build/nirai/panda3d/contrib/src/sceneeditor/seFileSaver.py
Normal file
|
@ -0,0 +1,915 @@
|
|||
####################################################################################################################################################
|
||||
# File Saving
|
||||
# This code saves the scene out as python code... the scene is stored in the various dictionaries in "dataHolder.py" ...the class "AllScene"
|
||||
#
|
||||
####################################################################################################################################################
|
||||
from pandac.PandaModules import *
|
||||
|
||||
from direct.showbase.ShowBaseGlobal import *
|
||||
import os
|
||||
import shutil
|
||||
import string
|
||||
|
||||
####################################################################################################################################################
|
||||
#### These modules are modified versions of Disney's equivalent modules
|
||||
#### We need to figure out a way to inherit their modules and overwrite what we need changed
|
||||
import seParticlePanel
|
||||
import seParticles
|
||||
import seParticleEffect
|
||||
import seForceGroup
|
||||
####################################################################################################################################################
|
||||
|
||||
class FileSaver:
|
||||
|
||||
####################################################################################################################################################
|
||||
# This class saves out the scene built with the scene editor as python code
|
||||
# There are dictionaries saved out to save the state of the scene for reloading it with the editor
|
||||
# Currently saving is supported for Models, Animations, Lights, Dummy Nodes
|
||||
# Attributes like parenting are also saved out
|
||||
# This class is actually instantiated in sceneEditor.py in the saveScene() method
|
||||
####################################################################################################################################################
|
||||
|
||||
def __init(self):
|
||||
pass
|
||||
|
||||
def SaveFile(self,AllScene,filename,dirname,reSaveFlag=0):
|
||||
|
||||
################################################################################################################################################
|
||||
# This function takes the "dataHolder" instance "AllScene" which has dictionaries containing scene information
|
||||
# The filename is where the scene will be written to
|
||||
################################################################################################################################################
|
||||
|
||||
i1=" " # indentation
|
||||
i2=i1+i1 # double indentation
|
||||
out_file = open(filename,"w")
|
||||
print "dirname:" + dirname
|
||||
if( not os.path.isdir(dirname)):
|
||||
os.mkdir(dirname)
|
||||
savepathname=Filename(filename)
|
||||
self.savepath=savepathname.getBasenameWoExtension()
|
||||
out_file.write("##########################################################################################################\n")
|
||||
out_file.write("# Auto Generated Code by Scene Editor\n")
|
||||
out_file.write("# Edit with caution\n")
|
||||
out_file.write("# Using this file in your code:\n")
|
||||
out_file.write("# For example, if you have named this file as \"myscene.py\"\n")
|
||||
out_file.write("# Do the following:\n")
|
||||
out_file.write("# from myscene import * \n")
|
||||
out_file.write("# theScene=SavedScene() #instantiate the class\n")
|
||||
out_file.write("# IMPORTANT: All the documentation below refers to \"theScene\" as the instance of SavedScene()\n")
|
||||
out_file.write("##########################################################################################################\n\n")
|
||||
|
||||
out_file.write("##########################################################################################################\n")
|
||||
out_file.write("# Import Panda Modules\n")
|
||||
out_file.write("##########################################################################################################\n")
|
||||
out_file.write("from direct.directbase.DirectStart import * # Core functionality for running the \"show\"\n")
|
||||
out_file.write("from direct.actor import Actor # Importing models with animations\n")
|
||||
out_file.write("from direct.directutil import Mopath # Motion Paths\n")
|
||||
out_file.write("from direct.interval import MopathInterval # Motion Paths\n")
|
||||
out_file.write("from direct.interval.IntervalGlobal import * # Intervals for interpolation, sequencing and parallelization\n")
|
||||
out_file.write("from direct.particles import ParticleEffect # Particle Systems\n")
|
||||
out_file.write("from direct.particles import ForceGroup # Forces acting on Particles\n")
|
||||
out_file.write("from direct.particles import Particles\n\n")
|
||||
out_file.write("##########################################################################################################\n")
|
||||
out_file.write("# This class stores the entire scene\n")
|
||||
out_file.write("##########################################################################################################\n\n")
|
||||
out_file.write("class SavedScene(DirectObject): # We inherit from DirectObject so that we can use self.accept method to catch messages\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"# These dictionaries are required for re-loading a scene in the editor\n")
|
||||
out_file.write(i1+"# They can be used to access the objects as well\n\n")
|
||||
out_file.write(i1+"ModelDic={}# Stores all the models and static geometry\n")
|
||||
out_file.write(i1+"ModelRefDic={}# Stores the paths to the models\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"ActorDic={}# Stores all the actors\n")
|
||||
out_file.write(i1+"ActorRefDic={}# Stores the paths to the actors\n")
|
||||
out_file.write(i1+"ActorAnimsDic={}# Stores the animations for each actor\n")
|
||||
out_file.write(i1+"blendAnimDict={}# Stores all the blended animations\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"LightDict={}# Stores all the lights\n")
|
||||
out_file.write(i1+"LightTypes={}# Stores types for the lights\n")
|
||||
out_file.write(i1+"LightNodes={}# Stores the actual nodes for the lights\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"dummyDict={}# Stores dummies\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"collisionDict={}# Stores Collision information\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"curveDict={}# Stores Mopath information\n")
|
||||
out_file.write(i1+"curveIntervals=[]# Stores list of mopath intervals\n")
|
||||
out_file.write(i1+"curveRefColl=[]# Stores paths to mopaths\n")
|
||||
out_file.write(i1+"curveIntervalsDict={}# Stores mopath intervals\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"particleDict={}# Stores particles\n")
|
||||
out_file.write(i1+"particleNodes={}# Stores particle nodes\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"#Light Count\n")
|
||||
out_file.write(i1+"ambientCount=0\n")
|
||||
out_file.write(i1+"directionalCount=0\n")
|
||||
out_file.write(i1+"pointCount=0\n")
|
||||
out_file.write(i1+"spotCount=0\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"#Lighting Attribute\n")
|
||||
out_file.write(i1+"lightAttrib = LightAttrib.makeAllOff()# Initialize lighting\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"CollisionHandler=CollisionHandlerEvent()# Setup a Collision Handler\n")
|
||||
|
||||
out_file.write(i1+"##########################################################################################################\n")
|
||||
out_file.write(i1+"# Constructor: this is run first when you instantiate the SavedScene class\n")
|
||||
out_file.write(i1+"##########################################################################################################\n")
|
||||
out_file.write(i1+"def __init__(self,loadmode=1,seParticleEffect=None,seParticles=None,executionpath=None):# loadmode 0 specifies that this file is being loaded by the scene editor and it passes its own versions of the particle fx modules\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"self.loadmode=loadmode\n")
|
||||
out_file.write(i2+"self.seParticleEffect=seParticleEffect\n")
|
||||
out_file.write(i2+"self.seParticles=seParticles\n")
|
||||
out_file.write(i2+"self.executionpath=executionpath\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"base.enableParticles()# Enable Particle effects\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"self.cTrav = CollisionTraverser() # Setup a traverser for collisions\n")
|
||||
out_file.write(i2+"base.cTrav = self.cTrav\n")
|
||||
out_file.write(i2+"self.CollisionHandler.setInPattern(\"enter%in\")# The message to be raised when something enters a collision node\n")
|
||||
out_file.write(i2+"self.CollisionHandler.setOutPattern(\"exit%in\")# The message to be raised when something exits a collision node\n")
|
||||
out_file.write("\n")
|
||||
####################################################################################################################################################
|
||||
# Save Models
|
||||
####################################################################################################################################################
|
||||
|
||||
out_file.write(i2+"##########################################################################################################\n")
|
||||
out_file.write(i2+"# Code for all the models\n")
|
||||
out_file.write(i2+"# To access these models:\n")
|
||||
out_file.write(i2+"# theScene.ModelDic[\"'Model_Name\"']\n")
|
||||
out_file.write(i2+"# where theScene is the SavedScene class instance\n")
|
||||
out_file.write(i2+"# Properties saved include:\n")
|
||||
out_file.write(i2+"# Transformations\n")
|
||||
out_file.write(i2+"# Alpha and color\n")
|
||||
out_file.write(i2+"# Parent and child information\n")
|
||||
out_file.write(i2+"##########################################################################################################\n")
|
||||
|
||||
for model in AllScene.ModelDic:
|
||||
out_file.write("\n")
|
||||
modelS=str(model)
|
||||
|
||||
if(1): # This is kept for now... perhaps later some sort of check might have to be enforced based on loadMode
|
||||
#Loading Code
|
||||
out_file.write(i2+"# Loading model's egg file\n")
|
||||
#out_file.write(i2+ "self."+ modelS + "=loader.loadModel(\'" + AllScene.ModelRefDic[model].getFullpath() + "\')\n")#Absolute Paths
|
||||
|
||||
newpath = dirname + "/" + AllScene.ModelRefDic[model].getBasename()
|
||||
newpathF=Filename(newpath)
|
||||
newpathSpecific=newpathF.toOsSpecific()
|
||||
|
||||
# Copy all the textures referenced by this file over to the relative directory
|
||||
fnamelist=[]
|
||||
modelData=EggData()
|
||||
modelData.read(AllScene.ModelRefDic[model])
|
||||
textures=EggTextureCollection()
|
||||
textures.findUsedTextures(modelData)
|
||||
for index in range(textures.getNumTextures()):
|
||||
texture=textures.getTexture(index)
|
||||
texfilename=texture.getFilename()
|
||||
fnamelist.append(texfilename.getFullpath())
|
||||
oldFilename=Filename(Filename(AllScene.ModelRefDic[model].getDirname()),texfilename)
|
||||
if(not oldFilename.isRegularFile()):
|
||||
if(texfilename.resolveFilename(getTexturePath(),"")):
|
||||
oldFilename=texfilename
|
||||
oldtexpath=oldFilename.toOsSpecific()
|
||||
|
||||
newtexpath=dirname + "/" + texfilename.getBasename()
|
||||
newtexpathF=Filename(newtexpath)
|
||||
newtexpathSpecific=newtexpathF.toOsSpecific()
|
||||
|
||||
print "TEXTURE SAVER:: copying" + oldtexpath + " to " + newtexpathSpecific
|
||||
if(oldtexpath != newtexpathSpecific):
|
||||
shutil.copyfile(oldtexpath,newtexpathSpecific)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Copy the file over to the relative directory
|
||||
oldModelpath=AllScene.ModelRefDic[model].toOsSpecific()
|
||||
print "FILESAVER:: copying from " + AllScene.ModelRefDic[model].toOsSpecific() + "to" + newpathSpecific
|
||||
if(oldModelpath!=newpathSpecific):
|
||||
shutil.copyfile(oldModelpath,newpathSpecific)
|
||||
|
||||
|
||||
e=EggData()
|
||||
e.read(AllScene.ModelRefDic[model])
|
||||
etc=EggTextureCollection()
|
||||
etc.extractTextures(e)
|
||||
for index in range(len(fnamelist)):
|
||||
print fnamelist[index]
|
||||
tex=etc.findFilename(Filename(fnamelist[index]))
|
||||
fn=Filename(tex.getFilename())
|
||||
fn.setDirname("")
|
||||
tex.setFilename(fn)
|
||||
e.writeEgg(Filename.fromOsSpecific(newpathSpecific))
|
||||
|
||||
|
||||
|
||||
out_file.write(i2+"if(self.loadmode==1):\n")
|
||||
out_file.write(i2+i1+ "self."+ modelS + "=loader.loadModel(\'" + self.savepath + "/" + AllScene.ModelRefDic[model].getBasename() + "')\n")#Relative Path
|
||||
out_file.write(i2+"else:\n")
|
||||
out_file.write(i2+i1+ "self."+ modelS + "=loader.loadModel(self.executionpath + \'/" + AllScene.ModelRefDic[model].getBasename() + "')\n")#Relative Path with execution point specified by the invoking-level-editor
|
||||
|
||||
#Transformation Code
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"# Transforming the model\n")
|
||||
out_file.write(i2+ "self."+ modelS + ".setPosHprScale(%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f)\n"% (AllScene.ModelDic[model].getX(),AllScene.ModelDic[model].getY(),AllScene.ModelDic[model].getZ(),AllScene.ModelDic[model].getH(),AllScene.ModelDic[model].getP(),AllScene.ModelDic[model].getR(),AllScene.ModelDic[model].getSx(),AllScene.ModelDic[model].getSy(),AllScene.ModelDic[model].getSz()))
|
||||
|
||||
if(AllScene.ModelDic[model].hasTransparency()):
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"# Alpha\n")
|
||||
out_file.write(i2+ "self."+ modelS + ".setTransparency(1)\n")
|
||||
clr=AllScene.ModelDic[model].getColor()
|
||||
out_file.write(i2+ "self."+ modelS + ".setColor(%.4f,%.4f,%.4f,%.4f)\n"%(clr.getX(),clr.getY(),clr.getZ(),clr.getW()))
|
||||
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+ "# Reparent To Render for now and later we update all the parentings\n")
|
||||
out_file.write(i2+ "self."+ modelS + ".reparentTo(render)\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+ "# Save Metadata...can be retrieved by doing theScene.ModelDic[\"Model_Name\"].getTag(\"Metadata\")\n")
|
||||
out_file.write(i2+ "self."+ modelS + ".setTag(\"Metadata\",\"" + AllScene.ModelDic[model].getTag("Metadata") + "\")\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+ "# Fill in the dictionaries which are used by level Ed to reload state\n")
|
||||
out_file.write(i2+ "self.ModelDic[\'" + modelS + "\']=self." + AllScene.ModelDic[model].getName()+"\n")
|
||||
#out_file.write(i2+ "self.ModelRefDic[\'" + modelS + "\']=Filename(\'"+ AllScene.ModelRefDic[model].getFullpath() +"\')\n")# The old Absolute Path way
|
||||
out_file.write(i2+ "self.ModelRefDic[\'" + modelS + "\']=\'"+ AllScene.ModelRefDic[model].getBasename() +"\'\n")# Relative paths
|
||||
out_file.write(i2+ "self.ModelDic[\'"+ modelS + "\'].setName(\'"+ modelS +"\')\n")
|
||||
out_file.write("\n")
|
||||
|
||||
####################################################################################################################################################
|
||||
# Save Dummies
|
||||
####################################################################################################################################################
|
||||
out_file.write(i2+"##########################################################################################################\n")
|
||||
out_file.write(i2+"# Code for all the Dummy Objects\n")
|
||||
out_file.write(i2+"# To access the dummies\n")
|
||||
out_file.write(i2+"# theScene.dummyDict['Dummy_Name']\n")
|
||||
out_file.write(i2+"##########################################################################################################\n")
|
||||
for dummy in AllScene.dummyDict:
|
||||
out_file.write("\n")
|
||||
dummyS=str(dummy)
|
||||
|
||||
if(1): # This is kept for now... perhaps later some sort of check might have to be enforced based on loadMode
|
||||
out_file.write(i2+ "self."+ dummyS + "=loader.loadModel(\"models/misc/sphere\")\n")
|
||||
#Transformation Code
|
||||
out_file.write(i2+"# Transforming the Dummy\n")
|
||||
out_file.write(i2+ "self."+ dummyS + ".setPosHprScale(%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f)\n"% (AllScene.dummyDict[dummy].getX(),AllScene.dummyDict[dummy].getY(),AllScene.dummyDict[dummy].getZ(),AllScene.dummyDict[dummy].getH(),AllScene.dummyDict[dummy].getP(),AllScene.dummyDict[dummy].getR(),AllScene.dummyDict[dummy].getSx(),AllScene.dummyDict[dummy].getSy(),AllScene.dummyDict[dummy].getSz()))
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+ "# Fill in the dictionaries which are used by level Ed to reload state\n")
|
||||
out_file.write(i2+ "self.dummyDict[\'" + dummyS + "\']=self." + AllScene.dummyDict[dummy].getName()+"\n")
|
||||
out_file.write(i2+ "self.dummyDict[\'"+ dummyS + "\'].setName(\'"+ dummyS +"\')\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+ "# Save Metadata...can be retrieved by doing theScene.dummyDict[\"Dummy_Name\"].getTag(\"Metadata\")\n")
|
||||
out_file.write(i2+ "self."+ dummyS + ".setTag(\"Metadata\",\"" + AllScene.dummyDict[dummy].getTag("Metadata") + "\")\n")
|
||||
out_file.write("\n")
|
||||
|
||||
####################################################################################################################################################
|
||||
# Saving Actors and their animations
|
||||
####################################################################################################################################################
|
||||
out_file.write(i2+"##########################################################################################################\n")
|
||||
out_file.write(i2+"# Code for all the Actors and animations\n")
|
||||
out_file.write(i2+"# To access the Actors\n")
|
||||
out_file.write(i2+"# theScene.ActorDic[\'Actor_Name\']\n")
|
||||
out_file.write(i2+"# theScene.ActorDic[\'Actor_Name\'].play(\'Animation_Name\')\n")
|
||||
out_file.write(i2+"##########################################################################################################\n")
|
||||
for actor in AllScene.ActorDic:
|
||||
out_file.write("\n")
|
||||
actorS=str(actor)
|
||||
|
||||
if(1): # This is kept for now... perhaps later some sort of check might have to be enforced based on loadMode
|
||||
#out_file.write(i2+ "self."+ actorS + "=Actor.Actor(\'"+ AllScene.ActorRefDic[actor].getFullpath() + "\')\n")# The old way with absolute paths
|
||||
|
||||
|
||||
newpath = dirname + "/" + AllScene.ActorRefDic[actor].getBasename()
|
||||
newpathF=Filename(newpath)
|
||||
newpathSpecific=newpathF.toOsSpecific()
|
||||
|
||||
# Copy all the textures referenced by this file over to the relative directory
|
||||
actorfnamelist=[]
|
||||
actorData=EggData()
|
||||
actorData.read(AllScene.ActorRefDic[actor])
|
||||
textures=EggTextureCollection()
|
||||
textures.findUsedTextures(actorData)
|
||||
for index in range(textures.getNumTextures()):
|
||||
texture=textures.getTexture(index)
|
||||
texfilename=texture.getFilename()
|
||||
actorfnamelist.append(texfilename.getFullpath())
|
||||
|
||||
oldFilename=Filename(Filename(AllScene.ActorRefDic[actor].getDirname()),texfilename)
|
||||
if(not oldFilename.isRegularFile()):
|
||||
if(texfilename.resolveFilename(getTexturePath(),"")):
|
||||
oldFilename=texfilename
|
||||
oldtexpath=oldFilename.toOsSpecific()
|
||||
|
||||
|
||||
newtexpath=dirname + "/" + texfilename.getBasename()
|
||||
newtexpathF=Filename(newtexpath)
|
||||
newtexpathSpecific=newtexpathF.toOsSpecific()
|
||||
print "TEXTURE SAVER:: copying" + oldtexpath + " to " + newtexpathSpecific
|
||||
if(oldtexpath != newtexpathSpecific):
|
||||
shutil.copyfile(oldtexpath,newtexpathSpecific)
|
||||
|
||||
|
||||
# Copy the file over to the relative directory
|
||||
oldActorpath=AllScene.ActorRefDic[actor].toOsSpecific()
|
||||
print "FILESAVER:: copying from " + AllScene.ActorRefDic[actor].toOsSpecific() + "to" + newpathSpecific
|
||||
if(oldActorpath!=newpathSpecific):
|
||||
shutil.copyfile(oldActorpath,newpathSpecific)
|
||||
|
||||
|
||||
e=EggData()
|
||||
e.read(AllScene.ActorRefDic[actor])
|
||||
etc=EggTextureCollection()
|
||||
etc.extractTextures(e)
|
||||
for index in range(len(actorfnamelist)):
|
||||
print actorfnamelist[index]
|
||||
tex=etc.findFilename(Filename(actorfnamelist[index]))
|
||||
fn=Filename(tex.getFilename())
|
||||
fn.setDirname("")
|
||||
tex.setFilename(fn)
|
||||
e.writeEgg(Filename.fromOsSpecific(newpathSpecific))
|
||||
|
||||
|
||||
|
||||
out_file.write(i2+"if(self.loadmode==1):\n")
|
||||
out_file.write(i2+i1+ "self."+ actorS + "=Actor.Actor(\'" + self.savepath + "/" + AllScene.ActorRefDic[actor].getBasename() + "')\n")#Relative Path
|
||||
out_file.write(i2+"else:\n")
|
||||
out_file.write(i2+i1+ "self."+ actorS + "=Actor.Actor(self.executionpath + \'/" + AllScene.ActorRefDic[actor].getBasename() + "')\n")#Relative Path with execution point specified by the invoking-level-editor
|
||||
|
||||
#Transformation Code
|
||||
out_file.write(i2+"# Transforming the Actor\n")
|
||||
out_file.write(i2+ "self."+ actorS + ".setPosHprScale(%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f)\n"% (AllScene.ActorDic[actor].getX(),AllScene.ActorDic[actor].getY(),AllScene.ActorDic[actor].getZ(),AllScene.ActorDic[actor].getH(),AllScene.ActorDic[actor].getP(),AllScene.ActorDic[actor].getR(),AllScene.ActorDic[actor].getSx(),AllScene.ActorDic[actor].getSy(),AllScene.ActorDic[actor].getSz()))
|
||||
|
||||
if(AllScene.ActorDic[actor].hasTransparency()):
|
||||
out_file.write(i2+"# Alpha\n")
|
||||
out_file.write(i2+ "self."+ actorS + ".setTransparency(1)\n")
|
||||
clr=AllScene.ActorDic[actor].getColor()
|
||||
out_file.write(i2+ "self."+ actorS + ".setColor(%.4f,%.4f,%.4f,%.4f)\n"%(clr.getX(),clr.getY(),clr.getZ(),clr.getW()))
|
||||
|
||||
out_file.write(i2+ "self."+ actorS + ".reparentTo(render)\n")
|
||||
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+ "# Save Metadata...can be retrieved by doing theScene.ActorDic[\"Actor_Name\"].getTag(\"Metadata\")\n")
|
||||
out_file.write(i2+ "self."+ actorS + ".setTag(\"Metadata\",\"" + AllScene.ActorDic[actor].getTag("Metadata") + "\")\n")
|
||||
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+ "# Fill in the dictionaries which are used by level Ed to reload state\n")
|
||||
ActorAnimations=AllScene.getAnimationDictFromActor(actor)
|
||||
ActorAnimationsInvoke={}
|
||||
|
||||
if(ActorAnimations!={}): #Check if a dictionary of animations exists for this actor
|
||||
for animation in ActorAnimations:
|
||||
#out_file.write(i2+ "self."+ actorS + ".loadAnims(" + str(ActorAnimations) +")\n") # Old way with absolute paths
|
||||
#Manakel 2/12/2004: solve the not empty but not defined animation case
|
||||
if not animation is None:
|
||||
print "ACTOR ANIMATIONS:" + ActorAnimations[animation]
|
||||
oldAnimPath=Filename(ActorAnimations[animation])
|
||||
oldAnim=oldAnimPath.toOsSpecific()
|
||||
dirOS=Filename(dirname)
|
||||
newAnim=dirOS.toOsSpecific() + "\\" + oldAnimPath.getBasename()
|
||||
print "ACTOR ANIM SAVER:: Comparing" + oldAnim +"and" + newAnim
|
||||
if(oldAnim!=newAnim):
|
||||
shutil.copyfile(oldAnim,newAnim)
|
||||
newAnimF=Filename.fromOsSpecific(newAnim)
|
||||
ActorAnimationsInvoke[animation]="self.executionpath +" + "/" +newAnimF.getBasename()
|
||||
ActorAnimations[animation]= self.savepath + "/" + newAnimF.getBasename()
|
||||
|
||||
|
||||
out_file.write(i2+"if(self.loadmode==1):\n")
|
||||
out_file.write(i2+ i1+"self."+ actorS + ".loadAnims(" + str(ActorAnimations) +")\n") # Now with new relative paths
|
||||
out_file.write(i2+"else:\n")
|
||||
theloadAnimString=str(ActorAnimationsInvoke)# We hack the "self.executionpath" part into the dictionary as a variable using string replace
|
||||
print "LOAD ANIM STRING BEFORE" + theloadAnimString
|
||||
theloadAnimString=theloadAnimString.replace('\'self.executionpath +','self.executionpath + \'')
|
||||
print "LOAD ANIM STRING AFTER" + theloadAnimString
|
||||
out_file.write(i2+ i1+"self."+ actorS + ".loadAnims(" + theloadAnimString +")\n") # Now with new relative paths based on editor invocation
|
||||
|
||||
out_file.write(i2+ "self.ActorDic[\'" + actorS + "\']=self." + AllScene.ActorDic[actor].getName()+"\n")
|
||||
#out_file.write(i2+ "self.ActorRefDic[\'" + actorS + "\']=Filename(\'"+AllScene.ActorRefDic[actor].getFullpath() +"\')\n") # Old way with absolute paths
|
||||
out_file.write(i2+ "self.ActorRefDic[\'" + actorS + "\']=\'"+ AllScene.ActorRefDic[actor].getBasename() +"\'\n")# Relative paths
|
||||
out_file.write(i2+ "self.ActorDic[\'"+ actorS + "\'].setName(\'"+ actorS +"\')\n")
|
||||
if(AllScene.blendAnimDict.has_key(actor)): # Check if a dictionary of blended animations exists
|
||||
out_file.write(i2+ "self.blendAnimDict[\"" + actorS +"\"]=" + str(AllScene.blendAnimDict[actor]) + "\n")
|
||||
|
||||
|
||||
out_file.write("\n")
|
||||
|
||||
####################################################################################################################################################
|
||||
# Collsion Node Saving
|
||||
####################################################################################################################################################
|
||||
|
||||
out_file.write(i2+"##########################################################################################################\n")
|
||||
out_file.write(i2+"# Code for setting up Collision Nodes\n")
|
||||
out_file.write(i2+"# To use collision detection:\n")
|
||||
out_file.write(i2+"# You must set up your own bitmasking and event handlers, the traverser \"cTrav\" is created for you at the top\n")
|
||||
out_file.write(i2+"# The collision nodes are stored in collisionDict\n")
|
||||
out_file.write(i2+"##########################################################################################################\n\n")
|
||||
for collnode in AllScene.collisionDict:
|
||||
collnodeS=str(collnode)
|
||||
solid=AllScene.collisionDict[collnode].node().getSolid(0)
|
||||
nodetype=solid.getType().getName()
|
||||
|
||||
if(nodetype=="CollisionSphere"): #Save Collison Sphere
|
||||
out_file.write(i2+"collSolid=CollisionSphere(%.3f,%.3f,%.3f,%.3f)\n"%(solid.getCenter().getX(),solid.getCenter().getY(),solid.getCenter().getZ(),solid.getRadius()))
|
||||
pass
|
||||
elif(nodetype=="CollisionPolygon"): #Save Collison Polygon
|
||||
|
||||
ax=AllScene.collisionDict[collnode].getTag("A_X")
|
||||
ay=AllScene.collisionDict[collnode].getTag("A_Y")
|
||||
az=AllScene.collisionDict[collnode].getTag("A_Z")
|
||||
|
||||
bx=AllScene.collisionDict[collnode].getTag("B_X")
|
||||
by=AllScene.collisionDict[collnode].getTag("B_Y")
|
||||
bz=AllScene.collisionDict[collnode].getTag("B_Z")
|
||||
|
||||
cx=AllScene.collisionDict[collnode].getTag("C_X")
|
||||
cy=AllScene.collisionDict[collnode].getTag("C_Y")
|
||||
cz=AllScene.collisionDict[collnode].getTag("C_Z")
|
||||
|
||||
out_file.write(i2+"pointA = Point3(" + ax + "," + ay + "," + az + ")\n")
|
||||
out_file.write(i2+"pointB = Point3(" + bx + "," + by + "," + bz + ")\n")
|
||||
out_file.write(i2+"pointC = Point3(" + cx + "," + cy + "," + cz + ")\n")
|
||||
out_file.write(i2+"collSolid=CollisionPolygon(pointA, pointB, pointC)\n")
|
||||
|
||||
pass
|
||||
|
||||
elif(nodetype=="CollisionSegment"): #Save Collison Segment
|
||||
A=AllScene.collisionDict[collnode].node().getSolid(0).getPointA()
|
||||
B=AllScene.collisionDict[collnode].node().getSolid(0).getPointB()
|
||||
|
||||
out_file.write(i2+"pointA = Point3(%.3f,%.3f,%.3f)\n"%(A.getX(),A.getY(),A.getZ()))
|
||||
out_file.write(i2+"pointB = Point3(%.3f,%.3f,%.3f)\n"%(B.getX(),B.getY(),B.getZ()))
|
||||
out_file.write(i2+"collSolid=CollisionSegment()\n")
|
||||
out_file.write(i2+"collSolid.setPointA(pointA)\n")
|
||||
out_file.write(i2+"collSolid.setFromLens(base.cam.node(),Point2(-1,1))\n")
|
||||
out_file.write(i2+"collSolid.setPointB(pointB)\n")
|
||||
|
||||
pass
|
||||
|
||||
elif(nodetype=="CollisionRay"): #Save Collison Ray
|
||||
P = AllScene.collisionDict[collnode].node().getSolid(0).getOrigin()
|
||||
V = AllScene.collisionDict[collnode].node().getSolid(0).getDirection()
|
||||
|
||||
out_file.write(i2+"point=Point3(%.3f,%.3f,%.3f)\n"%(P.getX(),P.getY(),P.getZ()))
|
||||
out_file.write(i2+"vector=Vec3(%.3f,%.3f,%.3f)\n"%(V.getX(),V.getY(),V.getZ()))
|
||||
out_file.write(i2+"collSolid=CollisionRay()\n")
|
||||
out_file.write(i2+"collSolid.setOrigin(point)\n")
|
||||
out_file.write(i2+"collSolid.setDirection(vector)\n")
|
||||
|
||||
pass
|
||||
else:
|
||||
print "Invalid Collision Node: " + nodetype
|
||||
out_file.write("\n")
|
||||
|
||||
|
||||
out_file.write(i2+"self." + collnodeS + "_Node" + "=CollisionNode(\""+collnodeS+"\")\n")
|
||||
out_file.write(i2+"self." + collnodeS + "_Node" + ".addSolid(collSolid)\n")
|
||||
out_file.write(i2+"base.cTrav.addCollider(self." + collnodeS + "_Node,self.CollisionHandler)\n")
|
||||
out_file.write("\n")
|
||||
|
||||
|
||||
|
||||
|
||||
####################################################################################################################################################
|
||||
# Light Saving
|
||||
####################################################################################################################################################
|
||||
out_file.write(i2+"##########################################################################################################\n")
|
||||
out_file.write(i2+"# Code for Lighting\n")
|
||||
out_file.write(i2+"# To manipulated lights:\n")
|
||||
out_file.write(i2+"# Manipulate the light node in theScene.LightNodes[\'Light_Name\']\n")
|
||||
out_file.write(i2+"##########################################################################################################\n\n")
|
||||
|
||||
LightList=AllScene.lightManager.getLightNodeList()
|
||||
for light in LightList:
|
||||
type = light.getType()
|
||||
if type == 'ambient':
|
||||
out_file.write(i2+"# Ambient Light\n")
|
||||
out_file.write (i2+ "self.ambientCount += 1\n")
|
||||
out_file.write (i2+ "alight = AmbientLight(\'"+ light.getName() +"\')\n")
|
||||
out_file.write (i2+ "alight.setColor(VBase4("+ str(light.getLightColor().getX())+ "," + str(light.getLightColor().getY())+ "," + str(light.getLightColor().getZ()) + "," + str(light.getLightColor().getW()) + "))\n")
|
||||
out_file.write (i2+ "self.lightAttrib=self.lightAttrib.addLight(alight)\n")
|
||||
out_file.write (i2+ "self."+light.getName()+"= render.attachNewNode(alight.upcastToPandaNode())\n")
|
||||
out_file.write (i2+ "self."+light.getName()+".setTag(\"Metadata\",\"" + light.getTag("Metadata") + "\")\n")
|
||||
out_file.write (i2+ "self.LightDict[\'" + light.getName() + "\']=alight\n")
|
||||
out_file.write (i2+ "self.LightTypes[\'" + light.getName() + "\']=\'" + type + "\'\n")
|
||||
out_file.write (i2+ "self.LightNodes[\'" + light.getName() + "\']=self." + light.getName() + "\n")
|
||||
out_file.write ("\n")
|
||||
elif type == 'directional':
|
||||
out_file.write(i2+"# Directional Light\n")
|
||||
out_file.write (i2+ "self.directionalCount += 1\n")
|
||||
out_file.write (i2+ "alight = DirectionalLight(\'"+ light.getName() + "\')\n")
|
||||
out_file.write (i2+ "alight.setColor(VBase4("+ str(light.getLightColor().getX())+ "," + str(light.getLightColor().getY())+ "," + str(light.getLightColor().getZ()) + "," + str(light.getLightColor().getW()) + "))\n")
|
||||
#out_file.write (i2+ "alight.setDirection(Vec3("+ str(light.getH())+ "," + str(light.getP())+ "," + str(light.getR()) + "))\n")
|
||||
#out_file.write (i2+ "alight.setPoint(Point3(" + str(light.getX()) + "," + str(light.getY()) + "," + str(light.getZ()) + "))\n")
|
||||
out_file.write (i2+ "alight.setSpecularColor(Vec4(" + str(light.getSpecColor().getX()) + "," + str(light.getSpecColor().getY()) + "," + str(light.getSpecColor().getZ()) + "," + str(light.getSpecColor().getW()) + "))\n")
|
||||
out_file.write (i2+ "self.lightAttrib=self.lightAttrib.addLight(alight)\n")
|
||||
out_file.write (i2+ "self."+light.getName()+ "= render.attachNewNode(alight.upcastToPandaNode())\n")
|
||||
out_file.write (i2+ "self."+light.getName()+ ".setPos(Point3(" + str(light.getX()) + "," + str(light.getY()) + "," + str(light.getZ()) + "))\n")
|
||||
out_file.write (i2+ "self."+light.getName()+ ".setHpr(Vec3("+ str(light.getH())+ "," + str(light.getP())+ "," + str(light.getR()) + "))\n")
|
||||
out_file.write (i2+ "self."+light.getName()+ ".setTag(\"Metadata\",\"" + light.getTag("Metadata") + "\")\n")
|
||||
#out_file.write (i2+ "alight.setPos
|
||||
out_file.write (i2+ "self.LightDict[\'" + light.getName() + "\']=alight\n")
|
||||
out_file.write (i2+ "self.LightTypes[\'" + light.getName() + "\']=\'" + type + "\'\n")
|
||||
out_file.write (i2+ "self.LightNodes[\'" + light.getName() + "\']=self." + light.getName() + "\n")
|
||||
out_file.write ("\n")
|
||||
elif type == 'point':
|
||||
out_file.write(i2+"# Point Light\n")
|
||||
out_file.write (i2+ "self.pointCount += 1\n")
|
||||
out_file.write (i2+ "alight = PointLight(\'"+ light.getName() +"\')\n")
|
||||
out_file.write (i2+ "alight.setColor(VBase4("+ str(light.getLightColor().getX())+ "," + str(light.getLightColor().getY())+ "," + str(light.getLightColor().getZ()) + "," + str(light.getLightColor().getW()) + "))\n")
|
||||
#out_file.write (i2+ "alight.setPoint(Point3(" + str(light.getX()) + "," + str(light.getY()) + "," + str(light.getZ()) + "))\n")
|
||||
out_file.write (i2+ "alight.setSpecularColor(Vec4(" + str(light.getSpecColor().getX()) + "," + str(light.getSpecColor().getY()) + "," + str(light.getSpecColor().getZ()) + "," + str(light.getSpecColor().getW()) + "))\n")
|
||||
out_file.write (i2+ "alight.setAttenuation(Vec3("+ str(light.getAttenuation().getX()) + "," + str(light.getAttenuation().getY()) + "," + str(light.getAttenuation().getZ()) + "))\n")
|
||||
out_file.write (i2+ "self.lightAttrib=self.lightAttrib.addLight(alight)\n")
|
||||
out_file.write (i2+ "self."+light.getName()+ "= render.attachNewNode(alight.upcastToPandaNode())\n")
|
||||
out_file.write (i2+ "self."+light.getName()+ ".setTag(\"Metadata\",\"" + light.getTag("Metadata") + "\")\n")
|
||||
out_file.write (i2+ "self."+light.getName()+ ".setPos(Point3(" + str(light.getX()) + "," + str(light.getY()) + "," + str(light.getZ()) + "))\n")
|
||||
out_file.write (i2+ "self.LightDict[\'" + light.getName() + "\']=alight\n")
|
||||
out_file.write (i2+ "self.LightTypes[\'" + light.getName() + "\']=\'" + type + "\'\n")
|
||||
out_file.write (i2+ "self.LightNodes[\'" + light.getName() + "\']=self." + light.getName() + "\n")
|
||||
out_file.write ("\n")
|
||||
elif type == 'spot':
|
||||
out_file.write(i2+"# Spot Light\n")
|
||||
out_file.write (i2+ "self.spotCount += 1\n")
|
||||
out_file.write (i2+ "alight = Spotlight(\'"+ light.getName() + "\')\n")
|
||||
out_file.write (i2+ "alight.setColor(VBase4("+ str(light.getLightColor().getX())+ "," + str(light.getLightColor().getY())+ "," + str(light.getLightColor().getZ()) + "," + str(light.getLightColor().getW()) + "))\n")
|
||||
out_file.write (i2+ "alens = PerspectiveLens()\n")
|
||||
out_file.write (i2+ "alight.setLens(alens)\n")
|
||||
out_file.write (i2+ "alight.setSpecularColor(Vec4(" + str(light.getSpecColor().getX()) + "," + str(light.getSpecColor().getY()) + "," + str(light.getSpecColor().getZ()) + "," + str(light.getSpecColor().getW()) + "))\n")
|
||||
out_file.write (i2+ "alight.setAttenuation(Vec3("+ str(light.getAttenuation().getX()) + "," + str(light.getAttenuation().getY()) + "," + str(light.getAttenuation().getZ()) + "))\n")
|
||||
out_file.write (i2+ "alight.setExponent(" +str(light.getExponent()) +")\n")
|
||||
out_file.write (i2+ "self.lightAttrib=self.lightAttrib.addLight(alight)\n")
|
||||
out_file.write (i2+ "self."+light.getName()+ "= render.attachNewNode(alight.upcastToLensNode())\n")
|
||||
out_file.write (i2+ "self."+light.getName()+ ".setTag(\"Metadata\",\"" + light.getTag("Metadata") + "\")\n")
|
||||
out_file.write (i2+ "self."+light.getName()+ ".setPos(Point3(" + str(light.getX()) + "," + str(light.getY()) + "," + str(light.getZ()) + "))\n")
|
||||
out_file.write (i2+ "self."+light.getName()+ ".setHpr(Vec3("+ str(light.getH())+ "," + str(light.getP())+ "," + str(light.getR()) + "))\n")
|
||||
out_file.write (i2+ "self.LightDict[\'" + light.getName() + "\']=alight\n")
|
||||
out_file.write (i2+ "self.LightTypes[\'" + light.getName() + "\']=\'" + type + "\'\n")
|
||||
out_file.write (i2+ "self.LightNodes[\'" + light.getName() + "\']=self." + light.getName() + "\n")
|
||||
out_file.write ("\n")
|
||||
else:
|
||||
out_file.write (i2+ "print \'Invalid light type\'")
|
||||
out_file.write (i2+ "return None")
|
||||
out_file.write("\n")
|
||||
|
||||
|
||||
|
||||
####################################################################################################################################################
|
||||
# Enable Lighting
|
||||
####################################################################################################################################################
|
||||
|
||||
out_file.write(i2+ "# Enable Ligthing\n")
|
||||
out_file.write(i2+ "render.node().setAttrib(self.lightAttrib)\n")
|
||||
out_file.write("\n")
|
||||
|
||||
|
||||
|
||||
####################################################################################################################################################
|
||||
# Initialize Particles for non scene editor mode
|
||||
####################################################################################################################################################
|
||||
|
||||
out_file.write(i2+"# Load Particle Effects. The parameters to this function are to allow us to use our modified versions of the Particle Effects modules when loading this file with the level editor\n")
|
||||
out_file.write(i2+"self.starteffects(self.loadmode,self.seParticleEffect,self.seParticles)\n")
|
||||
out_file.write("\n")
|
||||
|
||||
####################################################################################################################################################
|
||||
# Save Camera Settings
|
||||
####################################################################################################################################################
|
||||
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+ "# Save Camera Settings\n")
|
||||
out_file.write(i2+ "camera.setX(" + str(camera.getX()) + ")\n")
|
||||
out_file.write(i2+ "camera.setY(" + str(camera.getY()) + ")\n")
|
||||
out_file.write(i2+ "camera.setZ(" + str(camera.getZ()) + ")\n")
|
||||
out_file.write(i2+ "camera.setH(" + str(camera.getH()) + ")\n")
|
||||
out_file.write(i2+ "camera.setP(" + str(camera.getP()) + ")\n")
|
||||
out_file.write(i2+ "camera.setR(" + str(camera.getR()) + ")\n")
|
||||
out_file.write(i2+ "camera.getChild(0).node().getLens().setNear(" + str(camera.getChild(0).node().getLens().getNear()) + ")\n")
|
||||
out_file.write(i2+ "camera.getChild(0).node().getLens().setFar(" + str(camera.getChild(0).node().getLens().getFar()) + ")\n")
|
||||
out_file.write(i2+ "camera.getChild(0).node().getLens().setFov(VBase2(%.5f,%.5f))\n"% (camera.getChild(0).node().getLens().getHfov(),camera.getChild(0).node().getLens().getVfov()))
|
||||
FilmSize=camera.getChild(0).node().getLens().getFilmSize()
|
||||
out_file.write(i2+ "camera.getChild(0).node().getLens().setFilmSize(%.3f,%.3f)\n"%(FilmSize.getX(),FilmSize.getY()))
|
||||
out_file.write(i2+ "camera.getChild(0).node().getLens().setFocalLength(" + str(camera.getChild(0).node().getLens().getFocalLength()) + ")\n")
|
||||
out_file.write(i2+ "camera.setTag(\"Metadata\",\"" + camera.getTag("Metadata") + "\")\n")
|
||||
out_file.write(i2+ "camera.reparentTo(render)\n")
|
||||
out_file.write(i2+ "base.disableMouse()\n")
|
||||
self.bgColor=base.getBackgroundColor()
|
||||
out_file.write(i2+ "base.setBackgroundColor(%.3f,%.3f,%.3f)\n"%(self.bgColor.getX(),self.bgColor.getY(),self.bgColor.getZ()))
|
||||
out_file.write("\n")
|
||||
|
||||
|
||||
####################################################################################################################################################
|
||||
# Mopath Saving
|
||||
####################################################################################################################################################
|
||||
|
||||
out_file.write(i2+"##########################################################################################################\n")
|
||||
out_file.write(i2+"# Motion Paths\n")
|
||||
out_file.write(i2+"# Using Mopaths:\n")
|
||||
out_file.write(i2+"# theScene.curveIntervals[0].start() or .loop() will play curve with index 0\n")
|
||||
out_file.write(i2+"##########################################################################################################\n\n")
|
||||
|
||||
for node in AllScene.curveDict:
|
||||
curveCollection=AllScene.curveDict[node]
|
||||
curvenumber=0
|
||||
for curve in curveCollection:
|
||||
filestring=dirname+ "\\" + str(node)+"_curve_"+str(curvenumber)+".egg"
|
||||
f=Filename.fromOsSpecific(filestring)
|
||||
#filestring=f.getFullpath()# The old absolute path way
|
||||
filestring=f.getBasename() # The new relative path way
|
||||
curve.writeEgg(f)
|
||||
out_file.write(i2+"m=Mopath.Mopath()\n")
|
||||
|
||||
out_file.write(i2+"if(self.loadmode==1):\n")
|
||||
out_file.write(i2+i1+"m.loadFile(\"" + self.savepath +"/"+ filestring + "\")\n") # If just normally executed
|
||||
out_file.write(i2+"else:\n")
|
||||
out_file.write(i2+i1+"m.loadFile(self.executionpath + \"/"+ filestring + "\")\n") # If being invoked by level Ed
|
||||
|
||||
out_file.write(i2+"mp=MopathInterval(m,self." + str(node) + ")\n")
|
||||
out_file.write(i2+"self.curveIntervals.append(mp)\n")
|
||||
|
||||
out_file.write(i2+"if(self.loadmode==1):\n")
|
||||
out_file.write(i2+i1+"self.curveRefColl.append(\"" + self.savepath +"/"+ filestring +"\")\n")
|
||||
out_file.write(i2+"else:\n")
|
||||
out_file.write(i2+i1+"self.curveRefColl.append(self.executionpath + \"/"+ filestring +"\")\n")
|
||||
|
||||
curvenumber=curvenumber+1
|
||||
out_file.write(i2+"self.curveIntervalsDict[\"" + str(node) + "\"]=self.curveIntervals\n")
|
||||
out_file.write(i2+"self.curveDict[\"" + str(node) + "\"]=self.curveRefColl\n")
|
||||
|
||||
|
||||
####################################################################################################################################################
|
||||
# Lets do all the reparenting here so as to make sure everything that needed to load was loaded
|
||||
####################################################################################################################################################
|
||||
|
||||
|
||||
out_file.write(i2+"##########################################################################################################\n")
|
||||
out_file.write(i2+"# Reparenting\n")
|
||||
out_file.write(i2+"# A final pass is done on setting all the scenegraph hierarchy after all objects are laoded\n")
|
||||
out_file.write(i2+"##########################################################################################################\n\n")
|
||||
|
||||
for model in AllScene.ModelDic:
|
||||
modelS=str(model)
|
||||
parent=AllScene.ModelDic[model].getParent().getName()
|
||||
if(parent=="render" or parent=="camera"):
|
||||
out_file.write(i2+ "self."+ modelS + ".reparentTo(" + parent + ")\n")
|
||||
else:
|
||||
if(AllScene.particleDict.has_key(parent)):
|
||||
out_file.write(i2+ "self."+ modelS + ".reparentTo(self." + parent + ".getEffect())\n")
|
||||
else:
|
||||
out_file.write(i2+ "self."+ modelS + ".reparentTo(self." + parent + ")\n")
|
||||
out_file.write(i2+ "self.ModelDic[\'" + modelS + "\']=self." + AllScene.ModelDic[model].getName()+"\n")
|
||||
out_file.write(i2+"\n")
|
||||
|
||||
for dummy in AllScene.dummyDict:
|
||||
dummyS=str(dummy)
|
||||
parent=AllScene.dummyDict[dummy].getParent().getName()
|
||||
if(parent=="render" or parent=="camera"):
|
||||
out_file.write(i2+ "self."+ dummyS + ".reparentTo(" + parent + ")\n")
|
||||
else:
|
||||
if(AllScene.particleDict.has_key(parent)):
|
||||
out_file.write(i2+ "self."+ dummyS + ".reparentTo(self." + parent + ".getEffect())\n")
|
||||
else:
|
||||
out_file.write(i2+ "self."+ dummyS + ".reparentTo(self." + parent + ")\n")
|
||||
|
||||
out_file.write(i2+ "self.dummyDict[\'" + dummyS + "\']=self." + AllScene.dummyDict[dummy].getName()+"\n")
|
||||
out_file.write(i2+"\n")
|
||||
|
||||
for actor in AllScene.ActorDic:
|
||||
actorS=str(actor)
|
||||
parent=AllScene.ActorDic[actor].getParent().getName()
|
||||
if(parent=="render" or parent=="camera"):
|
||||
out_file.write(i2+ "self."+ actorS + ".reparentTo(" + parent + ")\n")
|
||||
else:
|
||||
if(AllScene.particleDict.has_key(parent)):
|
||||
out_file.write(i2+ "self."+ actorS + ".reparentTo(self." + parent + ".getEffect())\n")
|
||||
else:
|
||||
out_file.write(i2+ "self."+ actorS + ".reparentTo(self." + parent + ")\n")
|
||||
|
||||
out_file.write(i2+ "self.ActorDic[\'" + actorS + "\']=self." + AllScene.ActorDic[actor].getName()+"\n")
|
||||
out_file.write(i2+"\n")
|
||||
|
||||
|
||||
for collnode in AllScene.collisionDict:
|
||||
collnodeS=str(collnode)
|
||||
solid=AllScene.collisionDict[collnode].node().getSolid(0)
|
||||
nodetype=solid.getType().getName()
|
||||
parentname=AllScene.collisionDict[collnode].getParent().getName()
|
||||
if(parentname=="render" or parentname =="camera"):
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"]="+ parentname + ".attachNewNode(self." + collnodeS + "_Node)\n")
|
||||
else:
|
||||
#Manakel 2/12/2005: parent replaced by parent Name but why Parent name in partice and parent for other objects?
|
||||
if(AllScene.particleDict.has_key(parentname)):
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"]=self."+ parentname + "getEffect().attachNewNode(self." + collnodeS + "_Node)\n")
|
||||
else:
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"]=self."+ parentname + ".attachNewNode(self." + collnodeS + "_Node)\n")
|
||||
dictelem=AllScene.collisionDict[collnode]
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"].setPosHprScale(%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f)\n"%(dictelem.getX(),dictelem.getY(),dictelem.getZ(),dictelem.getH(),dictelem.getP(),dictelem.getR(),dictelem.getSx(),dictelem.getSy(),dictelem.getSz()))
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"].setTag(\"Metadata\",\"" + AllScene.collisionDict[collnode].getTag("Metadata") + "\")\n")
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"].show()\n")
|
||||
if(nodetype=="CollisionPolygon"): #Save Collison Polygon... the reason we need to use setTag here is because there is no inbuilt way of saving transforms for collision polys
|
||||
|
||||
ax=float(AllScene.collisionDict[collnode].getTag("A_X"))
|
||||
ay=float(AllScene.collisionDict[collnode].getTag("A_Y"))
|
||||
az=float(AllScene.collisionDict[collnode].getTag("A_Z"))
|
||||
|
||||
bx=float(AllScene.collisionDict[collnode].getTag("B_X"))
|
||||
by=float(AllScene.collisionDict[collnode].getTag("B_Y"))
|
||||
bz=float(AllScene.collisionDict[collnode].getTag("B_Z"))
|
||||
|
||||
cx=float(AllScene.collisionDict[collnode].getTag("C_X"))
|
||||
cy=float(AllScene.collisionDict[collnode].getTag("C_Y"))
|
||||
cz=float(AllScene.collisionDict[collnode].getTag("C_Z"))
|
||||
|
||||
out_file.write(i2+"pointA=Point3(%.3f,%.3f,%.3f)\n"%(ax,ay,az))
|
||||
out_file.write(i2+"pointB=Point3(%.3f,%.3f,%.3f)\n"%(bx,by,bz))
|
||||
out_file.write(i2+"pointC=Point3(%.3f,%.3f,%.3f)\n"%(cx,cy,cz))
|
||||
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"].setTag('A_X','%f'%pointA.getX())\n")
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"].setTag('A_Y','%f'%pointA.getY())\n")
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"].setTag('A_Z','%f'%pointA.getZ())\n")
|
||||
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"].setTag('B_X','%f'%pointB.getX())\n")
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"].setTag('B_Y','%f'%pointB.getY())\n")
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"].setTag('B_Z','%f'%pointB.getZ())\n")
|
||||
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"].setTag('C_X','%f'%pointC.getX())\n")
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"].setTag('C_Y','%f'%pointC.getY())\n")
|
||||
out_file.write(i2+"self.collisionDict[\"" + collnodeS + "\"].setTag('C_Z','%f'%pointC.getZ())\n")
|
||||
out_file.write(i2+"\n")
|
||||
|
||||
|
||||
for effect in AllScene.particleDict:
|
||||
parent=AllScene.particleNodes[effect].getParent().getName()
|
||||
if(parent=="render" or parent=="camera"):
|
||||
out_file.write(i2+"self.particleDict[\""+ str(effect) +"\"].reparentTo(" + parent + ")\n")
|
||||
else:
|
||||
out_file.write(i2+"self.particleDict[\""+ str(effect) +"\"].reparentTo(self." + parent + ")\n")
|
||||
out_file.write(i2+"\n")
|
||||
|
||||
|
||||
####################################################################################################################################################
|
||||
# Particle Saving
|
||||
####################################################################################################################################################
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"##########################################################################################################\n")
|
||||
out_file.write(i2+"# Particle Effects\n")
|
||||
out_file.write(i2+"# Using Particles:\n")
|
||||
out_file.write(i2+"# theScene.enableeffect(\"Effect_Name\")\n")
|
||||
out_file.write(i2+"##########################################################################################################\n\n")
|
||||
out_file.write(i1+"def starteffects(self,mode,seParticleEffect=None,seParticles=None):\n")
|
||||
for effect in AllScene.particleDict:
|
||||
effectS=str(effect)
|
||||
out_file.write(i2+ "self." + effectS + "=" + effectS + "(mode,seParticleEffect,seParticles)\n")
|
||||
out_file.write(i2+ "effect=self."+ effectS + ".getEffect()\n")
|
||||
out_file.write(i2+ "self.particleDict[\"" + effectS + "\"]=effect\n")
|
||||
out_file.write(i2+ "effect.reparentTo(render)\n")
|
||||
thenode=AllScene.particleNodes[effect]
|
||||
out_file.write(i2+ "self.particleDict[\"" + effectS + "\"].setPosHprScale(%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f)\n"%(thenode.getX(),thenode.getY(),thenode.getZ(),thenode.getH(),thenode.getP(),thenode.getR(),thenode.getSx(),thenode.getSy(),thenode.getSz()))
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"return\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"def enableeffect(self,effect_name):\n")
|
||||
out_file.write(i2+"self.particleDict[effect_name].enable()\n")
|
||||
out_file.write(i2+"return\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"def disableeffect(self,effect_name):\n")
|
||||
out_file.write(i2+"self.particleDict[effect_name].disable()\n")
|
||||
out_file.write(i2+"return\n")
|
||||
out_file.write("\n")
|
||||
|
||||
|
||||
####################################################################################################################################################
|
||||
# Animation Blending Methods
|
||||
####################################################################################################################################################
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"##########################################################################################################\n")
|
||||
out_file.write(i2+"# Animation Blending\n")
|
||||
out_file.write(i2+"# Using blending:\n")
|
||||
out_file.write(i2+"# theScene.playBlendAnim(actor,blendname)\n")
|
||||
out_file.write(i2+"# theScene.stopBlendAnim(actor,blendname)\n")
|
||||
out_file.write(i2+"# theScene.changeBlendAnim(actor,blendname,blend_amount)\n")
|
||||
out_file.write(i2+"##########################################################################################################\n\n")
|
||||
out_file.write(i1+"def playBlendAnim(self,actor,blendName,loop=0):\n")
|
||||
out_file.write(i2+"actor.enableBlend()\n")
|
||||
out_file.write(i2+"blendDicts=self.blendAnimDict[actor.getName()]\n")
|
||||
out_file.write(i2+"blendList=blendDicts[blendName]\n")
|
||||
out_file.write(i2+"actor.setControlEffect(blendList[0],blendList[2])\n")
|
||||
out_file.write(i2+"actor.setControlEffect(blendList[1],1.0-blendList[2])\n")
|
||||
out_file.write(i2+"if(loop):\n")
|
||||
out_file.write(i2+i1+"actor.loop(blendList[0])\n")
|
||||
out_file.write(i2+i1+"actor.loop(blendList[1])\n")
|
||||
out_file.write(i2+"else:\n")
|
||||
out_file.write(i2+i1+"actor.start(blendList[0])\n")
|
||||
out_file.write(i2+i1+"actor.start(blendList[1])\n")
|
||||
out_file.write("\n")
|
||||
|
||||
|
||||
out_file.write(i1+"def stopBlendAnim(self,actor,blendName):\n")
|
||||
out_file.write(i2+"blendDicts=self.blendAnimDict[actor.getName()]\n")
|
||||
out_file.write(i2+"blendList=blendDicts[blendName]\n")
|
||||
out_file.write(i2+"actor.stop(blendList[0])\n")
|
||||
out_file.write(i2+"actor.stop(blendList[1])\n")
|
||||
out_file.write("\n")
|
||||
|
||||
out_file.write(i1+"def changeBlending(self,actor,blendName,blending):\n")
|
||||
out_file.write(i2+"blendDicts=self.blendAnimDict[actor.getName()]\n")
|
||||
out_file.write(i2+"blendList=blendDicts[blendName]\n")
|
||||
out_file.write(i2+"blendList[2]=blending\n")
|
||||
out_file.write(i2+"self.blendAnimDict[actor.getName()]={blendName:[blendList[0],blendList[1],blending]}\n")
|
||||
out_file.write("\n")
|
||||
|
||||
|
||||
|
||||
####################################################################################################################################################
|
||||
# Hide and Show Methods
|
||||
####################################################################################################################################################
|
||||
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"##########################################################################################################\n")
|
||||
out_file.write(i2+"# Hide and Show Methods\n")
|
||||
out_file.write(i2+"# These will help you hide/show dummies, collision solids, effect nodes etc.\n")
|
||||
out_file.write(i2+"##########################################################################################################\n\n")
|
||||
|
||||
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"def hideDummies(self):\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"for dummy in self.dummyDict:\n")
|
||||
out_file.write(i2+i1+"self.dummyDict[dummy].reparentTo(hidden)\n")
|
||||
|
||||
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"def hideCollSolids(self):\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"for collSolid in self.collisionDict:\n")
|
||||
out_file.write(i2+i1+"self.collisionDict[collSolid].hide()\n")
|
||||
|
||||
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"def hideEffectNodes(self):\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"for effectnode in self.particleNodes:\n")
|
||||
out_file.write(i2+i1+"self.particleNodes[effectnode].hide()\n")
|
||||
|
||||
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"def showDummies(self):\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"for dummy in self.dummyDict:\n")
|
||||
out_file.write(i2+i1+"self.dummyDict[dummy].reparentTo(hidden)\n")
|
||||
|
||||
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"def showCollSolids(self):\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"for collSolid in self.collisionDict:\n")
|
||||
out_file.write(i2+i1+"self.collisionDict[collSolid].show()\n")
|
||||
|
||||
|
||||
out_file.write("\n")
|
||||
out_file.write(i1+"def showEffectNodes(self):\n")
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"for effectnode in self.particleNodes:\n")
|
||||
out_file.write(i2+i1+"self.particleNodes[effectnode].show()\n\n")
|
||||
|
||||
|
||||
##########################################################################################################
|
||||
# Saving Particle Parameters as a Class
|
||||
##########################################################################################################
|
||||
|
||||
out_file.write("\n")
|
||||
out_file.write(i2+"##########################################################################################################\n")
|
||||
out_file.write(i2+"# Particle Effects\n")
|
||||
out_file.write(i2+"# This is where effect parameters are saved in a class\n")
|
||||
out_file.write(i2+"# The class is then instantiated in the starteffects method and appended to the dictionaries\n")
|
||||
out_file.write(i2+"##########################################################################################################\n\n")
|
||||
|
||||
for effect in AllScene.particleDict:
|
||||
|
||||
out_file.write("\n\n")
|
||||
out_file.write("class " + str(effect) + ":\n")
|
||||
out_file.write(i1+"def __init__(self,mode=1,seParticleEffect=None,seParticles=None):\n")
|
||||
out_file.write(i2+"if(mode==0):\n")
|
||||
out_file.write(i2+i1+"self.effect=seParticleEffect.ParticleEffect()\n")
|
||||
out_file.write(i2+"else:\n")
|
||||
out_file.write(i2+i1+"self.effect=ParticleEffect.ParticleEffect()\n")
|
||||
AllScene.particleDict[effect].AppendConfig(out_file)
|
||||
#out_file.write(i2+"return self.effect\n")
|
||||
out_file.write("\n\n")
|
||||
out_file.write(i1+"def starteffect(self):\n")
|
||||
out_file.write(i2+"pass\n")
|
||||
out_file.write("\n\n")
|
||||
out_file.write(i1+"def stopeffect(self):\n")
|
||||
out_file.write(i2+"pass\n\n")
|
||||
out_file.write(i1+"def getEffect(self):\n")
|
||||
out_file.write(i2+"return self.effect\n\n")
|
||||
|
||||
|
||||
|
||||
#Un-comment the lines below to make this a stand-alone file
|
||||
#out_file.write("Scene=SavedScene()\n")
|
||||
#out_file.write("run()\n")
|
||||
|
||||
out_file.close()
|
||||
|
||||
|
134
build/nirai/panda3d/contrib/src/sceneeditor/seForceGroup.py
Normal file
134
build/nirai/panda3d/contrib/src/sceneeditor/seForceGroup.py
Normal file
|
@ -0,0 +1,134 @@
|
|||
from pandac.PandaModules import *
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from direct.showbase.PhysicsManagerGlobal import *
|
||||
#Manakel 2/12/2005: replace from pandac import by from pandac.PandaModules import
|
||||
from pandac.PandaModules import ForceNode
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
import sys
|
||||
|
||||
class ForceGroup(DirectObject):
|
||||
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('ForceGroup')
|
||||
id = 1
|
||||
|
||||
def __init__(self, name=None):
|
||||
"""__init__(self)"""
|
||||
|
||||
if (name == None):
|
||||
self.name = 'ForceGroup-%d' % ForceGroup.id
|
||||
ForceGroup.id += 1
|
||||
else:
|
||||
self.name = name
|
||||
|
||||
self.node = ForceNode.ForceNode(self.name)
|
||||
self.nodePath = NodePath(self.node)
|
||||
self.fEnabled = 0
|
||||
|
||||
self.particleEffect = None
|
||||
|
||||
def cleanup(self):
|
||||
self.node.clear()
|
||||
self.nodePath.removeNode()
|
||||
del self.nodePath
|
||||
del self.node
|
||||
del self.particleEffect
|
||||
|
||||
def enable(self):
|
||||
"""
|
||||
Convenience function to enable all forces in force group
|
||||
"""
|
||||
for i in range(self.node.getNumForces()):
|
||||
f = self.node.getForce(i)
|
||||
f.setActive(1)
|
||||
self.fEnabled = 1
|
||||
|
||||
def disable(self):
|
||||
"""
|
||||
Convenience function to disable all forces in force group
|
||||
"""
|
||||
for i in range(self.node.getNumForces()):
|
||||
f = self.node.getForce(i)
|
||||
f.setActive(0)
|
||||
self.fEnabled = 0
|
||||
|
||||
def isEnabled(self):
|
||||
return self.fEnabled
|
||||
|
||||
def addForce(self, force):
|
||||
"""addForce(self, force)"""
|
||||
self.node.addForce(force)
|
||||
if (self.particleEffect):
|
||||
self.particleEffect.addForce(force)
|
||||
|
||||
def removeForce(self, force):
|
||||
"""removeForce(self, force)"""
|
||||
self.node.removeForce(force)
|
||||
if (self.particleEffect != None):
|
||||
self.particleEffect.removeForce(force)
|
||||
|
||||
# Get/set
|
||||
def getName(self):
|
||||
return self.name
|
||||
def getNode(self):
|
||||
return self.node
|
||||
def getNodePath(self):
|
||||
return self.nodePath
|
||||
|
||||
# Utility functions
|
||||
def __getitem__(self, index):
|
||||
numForces = self.node.getNumForces()
|
||||
if ((index < 0) or (index >= numForces)):
|
||||
raise IndexError
|
||||
return self.node.getForce(index)
|
||||
|
||||
def __len__(self):
|
||||
return self.node.getNumForces()
|
||||
|
||||
def asList(self):
|
||||
l = []
|
||||
for i in range(self.node.getNumForces()):
|
||||
l.append(self.node.getForce(i))
|
||||
return l
|
||||
|
||||
def printParams(self, file = sys.stdout, targ = 'self'):
|
||||
i1=" "
|
||||
i2=i1+i1
|
||||
file.write(i2+'# Force parameters\n')
|
||||
for i in range(self.node.getNumForces()):
|
||||
f = self.node.getForce(i)
|
||||
fname = 'force%d' % i
|
||||
if isinstance(f, LinearForce):
|
||||
amplitude = f.getAmplitude()
|
||||
massDependent = f.getMassDependent()
|
||||
if isinstance(f, LinearCylinderVortexForce):
|
||||
file.write(i2+fname + ' = LinearCylinderVortexForce(%.4f, %.4f, %.4f, %.4f, %d)\n' % (f.getRadius(), f.getLength(), f.getCoef(), amplitude, massDependent))
|
||||
elif isinstance(f, LinearDistanceForce):
|
||||
radius = f.getRadius()
|
||||
falloffType = f.getFalloffType()
|
||||
ftype = 'FTONEOVERR'
|
||||
if (falloffType == LinearDistanceForce.FTONEOVERR):
|
||||
ftype = 'FTONEOVERR'
|
||||
elif (falloffType == LinearDistanceForce.FTONEOVERRSQUARED):
|
||||
ftype = 'FTONEOVERRSQUARED'
|
||||
elif (falloffType == LinearDistanceForce.FTONEOVERRCUBED):
|
||||
ftype = 'FTONEOVERRCUBED'
|
||||
forceCenter = f.getForceCenter()
|
||||
if isinstance(f, LinearSinkForce):
|
||||
file.write(i2+fname + ' = LinearSinkForce(Point3(%.4f, %.4f, %.4f), LinearDistanceForce.%s, %.4f, %.4f, %d)\n' % (forceCenter[0], forceCenter[1], forceCenter[2], ftype, radius, amplitude, massDependent))
|
||||
elif isinstance(f, LinearSourceForce):
|
||||
file.write(i2+fname + ' = LinearSourceForce(Point3(%.4f, %.4f, %.4f), LinearDistanceForce.%s, %.4f, %.4f, %d)\n' % (forceCenter[0], forceCenter[1], forceCenter[2], ftype, radius, amplitude, massDependent))
|
||||
elif isinstance(f, LinearFrictionForce):
|
||||
file.write(i2+fname + ' = LinearFrictionForce(%.4f, %.4f, %d)\n' % (f.getCoef(), amplitude, massDependent))
|
||||
elif isinstance(f, LinearJitterForce):
|
||||
file.write(i2+fname + ' = LinearJitterForce(%.4f, %d)\n' % (amplitude, massDependent))
|
||||
elif isinstance(f, LinearNoiseForce):
|
||||
file.write(i2+fname + ' = LinearNoiseForce(%.4f, %d)\n' % (amplitude, massDependent))
|
||||
elif isinstance(f, LinearVectorForce):
|
||||
vec = f.getLocalVector()
|
||||
file.write(i2+fname + ' = LinearVectorForce(Vec3(%.4f, %.4f, %.4f), %.4f, %d)\n' % (vec[0], vec[1], vec[2], amplitude, massDependent))
|
||||
elif isinstance(f, AngularForce):
|
||||
if isinstance(f, AngularVectorForce):
|
||||
vec = f.getQuat()
|
||||
file.write(i2+fname + ' = AngularVectorForce(Quat(%.4f, %.4f, %.4f))\n' % (vec[0], vec[1], vec[2], vec[3]))
|
||||
file.write(i2+fname + '.setActive(%d)\n' % f.getActive())
|
||||
file.write(i2+targ + '.addForce(%s)\n' % fname)
|
256
build/nirai/panda3d/contrib/src/sceneeditor/seGeometry.py
Normal file
256
build/nirai/panda3d/contrib/src/sceneeditor/seGeometry.py
Normal file
|
@ -0,0 +1,256 @@
|
|||
#################################################################
|
||||
# seGeometry.py
|
||||
# Originally from DirectGeometry.py
|
||||
# Altered by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#
|
||||
# We didn't change anything essential.
|
||||
# Just because we customized the seSession from DirectSession,
|
||||
# So we need related files can follow the change.
|
||||
# However, we don't want to change anything inside the original directool
|
||||
# to let them can work with our scene editor.
|
||||
# (If we do change original directools, it will force user has to install the latest version of OUR Panda)
|
||||
#
|
||||
#################################################################
|
||||
|
||||
from pandac.PandaModules import *
|
||||
from direct.directtools.DirectGlobals import *
|
||||
from direct.directtools.DirectUtil import *
|
||||
import math
|
||||
|
||||
class LineNodePath(NodePath):
|
||||
def __init__(self, parent = None, name = None,
|
||||
thickness = 1.0, colorVec = VBase4(1)):
|
||||
|
||||
# Initialize the superclass
|
||||
NodePath.__init__(self)
|
||||
|
||||
if parent is None:
|
||||
parent = hidden
|
||||
|
||||
# Attach a geomNode to the parent and set self to be
|
||||
# the resulting node path
|
||||
self.lineNode = GeomNode("lineNode")
|
||||
self.assign(parent.attachNewNode( self.lineNode ))
|
||||
if name:
|
||||
self.setName(name)
|
||||
|
||||
# Create a lineSegs object to hold the line
|
||||
ls = self.lineSegs = LineSegs()
|
||||
# Initialize the lineSegs parameters
|
||||
ls.setThickness(thickness)
|
||||
ls.setColor(colorVec)
|
||||
|
||||
def moveTo( self, *_args ):
|
||||
apply( self.lineSegs.moveTo, _args )
|
||||
|
||||
def drawTo( self, *_args ):
|
||||
apply( self.lineSegs.drawTo, _args )
|
||||
|
||||
def create( self, frameAccurate = 0 ):
|
||||
self.lineSegs.create( self.lineNode, frameAccurate )
|
||||
|
||||
def reset( self ):
|
||||
self.lineSegs.reset()
|
||||
self.lineNode.removeAllGeoms()
|
||||
|
||||
def isEmpty( self ):
|
||||
return self.lineSegs.isEmpty()
|
||||
|
||||
def setThickness( self, thickness ):
|
||||
self.lineSegs.setThickness( thickness )
|
||||
|
||||
def setColor( self, *_args ):
|
||||
apply( self.lineSegs.setColor, _args )
|
||||
|
||||
def setVertex( self, *_args):
|
||||
apply( self.lineSegs.setVertex, _args )
|
||||
|
||||
def setVertexColor( self, vertex, *_args ):
|
||||
apply( self.lineSegs.setVertexColor, (vertex,) + _args )
|
||||
|
||||
def getCurrentPosition( self ):
|
||||
return self.lineSegs.getCurrentPosition()
|
||||
|
||||
def getNumVertices( self ):
|
||||
return self.lineSegs.getNumVertices()
|
||||
|
||||
def getVertex( self, index ):
|
||||
return self.lineSegs.getVertex(index)
|
||||
|
||||
def getVertexColor( self ):
|
||||
return self.lineSegs.getVertexColor()
|
||||
|
||||
def drawArrow(self, sv, ev, arrowAngle, arrowLength):
|
||||
"""
|
||||
Do the work of moving the cursor around to draw an arrow from
|
||||
sv to ev. Hack: the arrows take the z value of the end point
|
||||
"""
|
||||
self.moveTo(sv)
|
||||
self.drawTo(ev)
|
||||
v = sv - ev
|
||||
# Find the angle of the line
|
||||
angle = math.atan2(v[1], v[0])
|
||||
# Get the arrow angles
|
||||
a1 = angle + deg2Rad(arrowAngle)
|
||||
a2 = angle - deg2Rad(arrowAngle)
|
||||
# Get the arrow points
|
||||
a1x = arrowLength * math.cos(a1)
|
||||
a1y = arrowLength * math.sin(a1)
|
||||
a2x = arrowLength * math.cos(a2)
|
||||
a2y = arrowLength * math.sin(a2)
|
||||
z = ev[2]
|
||||
self.moveTo(ev)
|
||||
self.drawTo(Point3(ev + Point3(a1x, a1y, z)))
|
||||
self.moveTo(ev)
|
||||
self.drawTo(Point3(ev + Point3(a2x, a2y, z)))
|
||||
|
||||
def drawArrow2d(self, sv, ev, arrowAngle, arrowLength):
|
||||
"""
|
||||
Do the work of moving the cursor around to draw an arrow from
|
||||
sv to ev. Hack: the arrows take the z value of the end point
|
||||
"""
|
||||
self.moveTo(sv)
|
||||
self.drawTo(ev)
|
||||
v = sv - ev
|
||||
# Find the angle of the line
|
||||
angle = math.atan2(v[2], v[0])
|
||||
# Get the arrow angles
|
||||
a1 = angle + deg2Rad(arrowAngle)
|
||||
a2 = angle - deg2Rad(arrowAngle)
|
||||
# Get the arrow points
|
||||
a1x = arrowLength * math.cos(a1)
|
||||
a1y = arrowLength * math.sin(a1)
|
||||
a2x = arrowLength * math.cos(a2)
|
||||
a2y = arrowLength * math.sin(a2)
|
||||
self.moveTo(ev)
|
||||
self.drawTo(Point3(ev + Point3(a1x, 0.0, a1y)))
|
||||
self.moveTo(ev)
|
||||
self.drawTo(Point3(ev + Point3(a2x, 0.0, a2y)))
|
||||
|
||||
def drawLines(self, lineList):
|
||||
"""
|
||||
Given a list of lists of points, draw a separate line for each list
|
||||
"""
|
||||
for pointList in lineList:
|
||||
apply(self.moveTo, pointList[0])
|
||||
for point in pointList[1:]:
|
||||
apply(self.drawTo, point)
|
||||
|
||||
##
|
||||
## Given a point in space, and a direction, find the point of intersection
|
||||
## of that ray with a plane at the specified origin, with the specified normal
|
||||
def planeIntersect (lineOrigin, lineDir, planeOrigin, normal):
|
||||
t = 0
|
||||
offset = planeOrigin - lineOrigin
|
||||
t = offset.dot(normal) / lineDir.dot(normal)
|
||||
hitPt = lineDir * t
|
||||
return hitPt + lineOrigin
|
||||
|
||||
def getNearProjectionPoint(nodePath):
|
||||
# Find the position of the projection of the specified node path
|
||||
# on the near plane
|
||||
origin = nodePath.getPos(SEditor.camera)
|
||||
# project this onto near plane
|
||||
if origin[1] != 0.0:
|
||||
return origin * (SEditor.dr.near / origin[1])
|
||||
else:
|
||||
# Object is coplaner with camera, just return something reasonable
|
||||
return Point3(0, SEditor.dr.near, 0)
|
||||
|
||||
def getScreenXY(nodePath):
|
||||
# Where does the node path's projection fall on the near plane
|
||||
nearVec = getNearProjectionPoint(nodePath)
|
||||
# Clamp these coordinates to visible screen
|
||||
nearX = CLAMP(nearVec[0], SEditor.dr.left, SEditor.dr.right)
|
||||
nearY = CLAMP(nearVec[2], SEditor.dr.bottom, SEditor.dr.top)
|
||||
# What percentage of the distance across the screen is this?
|
||||
percentX = (nearX - SEditor.dr.left)/SEditor.dr.nearWidth
|
||||
percentY = (nearY - SEditor.dr.bottom)/SEditor.dr.nearHeight
|
||||
# Map this percentage to the same -1 to 1 space as the mouse
|
||||
screenXY = Vec3((2 * percentX) - 1.0,nearVec[1],(2 * percentY) - 1.0)
|
||||
# Return the resulting value
|
||||
return screenXY
|
||||
|
||||
def getCrankAngle(center):
|
||||
# Used to compute current angle of mouse (relative to the coa's
|
||||
# origin) in screen space
|
||||
x = SEditor.dr.mouseX - center[0]
|
||||
y = SEditor.dr.mouseY - center[2]
|
||||
return (180 + rad2Deg(math.atan2(y,x)))
|
||||
|
||||
def relHpr(nodePath, base, h, p, r):
|
||||
# Compute nodePath2newNodePath relative to base coordinate system
|
||||
# nodePath2base
|
||||
mNodePath2Base = nodePath.getMat(base)
|
||||
# delta scale, orientation, and position matrix
|
||||
mBase2NewBase = Mat4()
|
||||
composeMatrix(mBase2NewBase, UNIT_VEC, VBase3(h,p,r), ZERO_VEC,
|
||||
CSDefault)
|
||||
# base2nodePath
|
||||
mBase2NodePath = base.getMat(nodePath)
|
||||
# nodePath2 Parent
|
||||
mNodePath2Parent = nodePath.getMat()
|
||||
# Compose the result
|
||||
resultMat = mNodePath2Base * mBase2NewBase
|
||||
resultMat = resultMat * mBase2NodePath
|
||||
resultMat = resultMat * mNodePath2Parent
|
||||
# Extract and apply the hpr
|
||||
hpr = Vec3(0)
|
||||
decomposeMatrix(resultMat, VBase3(), hpr, VBase3(),
|
||||
CSDefault)
|
||||
nodePath.setHpr(hpr)
|
||||
|
||||
# Quaternion interpolation
|
||||
def qSlerp(startQuat, endQuat, t):
|
||||
startQ = Quat(startQuat)
|
||||
destQuat = Quat.identQuat()
|
||||
# Calc dot product
|
||||
cosOmega = (startQ.getI() * endQuat.getI() +
|
||||
startQ.getJ() * endQuat.getJ() +
|
||||
startQ.getK() * endQuat.getK() +
|
||||
startQ.getR() * endQuat.getR())
|
||||
# If the above dot product is negative, it would be better to
|
||||
# go between the negative of the initial and the final, so that
|
||||
# we take the shorter path.
|
||||
if ( cosOmega < 0.0 ):
|
||||
cosOmega *= -1
|
||||
startQ.setI(-1 * startQ.getI())
|
||||
startQ.setJ(-1 * startQ.getJ())
|
||||
startQ.setK(-1 * startQ.getK())
|
||||
startQ.setR(-1 * startQ.getR())
|
||||
if ((1.0 + cosOmega) > Q_EPSILON):
|
||||
# usual case
|
||||
if ((1.0 - cosOmega) > Q_EPSILON):
|
||||
# usual case
|
||||
omega = math.acos(cosOmega)
|
||||
sinOmega = math.sin(omega)
|
||||
startScale = math.sin((1.0 - t) * omega)/sinOmega
|
||||
endScale = math.sin(t * omega)/sinOmega
|
||||
else:
|
||||
# ends very close
|
||||
startScale = 1.0 - t
|
||||
endScale = t
|
||||
destQuat.setI(startScale * startQ.getI() +
|
||||
endScale * endQuat.getI())
|
||||
destQuat.setJ(startScale * startQ.getJ() +
|
||||
endScale * endQuat.getJ())
|
||||
destQuat.setK(startScale * startQ.getK() +
|
||||
endScale * endQuat.getK())
|
||||
destQuat.setR(startScale * startQ.getR() +
|
||||
endScale * endQuat.getR())
|
||||
else:
|
||||
# ends nearly opposite
|
||||
destQuat.setI(-startQ.getJ())
|
||||
destQuat.setJ(startQ.getI())
|
||||
destQuat.setK(-startQ.getR())
|
||||
destQuat.setR(startQ.getK())
|
||||
startScale = math.sin((0.5 - t) * math.pi)
|
||||
endScale = math.sin(t * math.pi)
|
||||
destQuat.setI(startScale * startQ.getI() +
|
||||
endScale * endQuat.getI())
|
||||
destQuat.setJ(startScale * startQ.getJ() +
|
||||
endScale * endQuat.getJ())
|
||||
destQuat.setK(startScale * startQ.getK() +
|
||||
endScale * endQuat.getK())
|
||||
return destQuat
|
||||
|
170
build/nirai/panda3d/contrib/src/sceneeditor/seGrid.py
Normal file
170
build/nirai/panda3d/contrib/src/sceneeditor/seGrid.py
Normal file
|
@ -0,0 +1,170 @@
|
|||
#################################################################
|
||||
# seGrid.py
|
||||
# Originally from DirectGrid.py
|
||||
# Altered by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#
|
||||
# We didn't change anything essential.
|
||||
# Just because we customized the seSession from DirectSession,
|
||||
# So we need related files can follow the change.
|
||||
# However, we don't want to change anything inside the original directool
|
||||
# to let them can work with our scene editor.
|
||||
# (If we do change original directools, it will force user has to install the latest version of OUR Panda)
|
||||
#
|
||||
#################################################################
|
||||
from direct.showbase.DirectObject import *
|
||||
from direct.directtools.DirectUtil import *
|
||||
from seGeometry import *
|
||||
|
||||
class DirectGrid(NodePath,DirectObject):
|
||||
def __init__(self):
|
||||
# Initialize superclass
|
||||
NodePath.__init__(self)
|
||||
self.assign(hidden.attachNewNode('DirectGrid'))
|
||||
# Don't wireframe or light
|
||||
useDirectRenderStyle(self)
|
||||
|
||||
# Load up grid parts to initialize grid object
|
||||
# Polygon used to mark grid plane
|
||||
self.gridBack = loader.loadModel('models/misc/gridBack')
|
||||
self.gridBack.reparentTo(self)
|
||||
self.gridBack.setColor(0.5,0.5,0.5,0.5)
|
||||
|
||||
# Grid Lines
|
||||
self.lines = self.attachNewNode('gridLines')
|
||||
self.minorLines = LineNodePath(self.lines)
|
||||
self.minorLines.lineNode.setName('minorLines')
|
||||
self.minorLines.setColor(VBase4(0.3,0.55,1,1))
|
||||
self.minorLines.setThickness(1)
|
||||
|
||||
self.majorLines = LineNodePath(self.lines)
|
||||
self.majorLines.lineNode.setName('majorLines')
|
||||
self.majorLines.setColor(VBase4(0.3,0.55,1,1))
|
||||
self.majorLines.setThickness(5)
|
||||
|
||||
self.centerLines = LineNodePath(self.lines)
|
||||
self.centerLines.lineNode.setName('centerLines')
|
||||
self.centerLines.setColor(VBase4(1,0,0,0))
|
||||
self.centerLines.setThickness(3)
|
||||
|
||||
# Small marker to hilight snap-to-grid point
|
||||
self.snapMarker = loader.loadModel('models/misc/sphere')
|
||||
self.snapMarker.node().setName('gridSnapMarker')
|
||||
self.snapMarker.reparentTo(self)
|
||||
self.snapMarker.setColor(1,0,0,1)
|
||||
self.snapMarker.setScale(0.3)
|
||||
self.snapPos = Point3(0)
|
||||
|
||||
# Initialize Grid characteristics
|
||||
self.fXyzSnap = 1
|
||||
self.fHprSnap = 1
|
||||
self.gridSize = 100.0
|
||||
self.gridSpacing = 5.0
|
||||
self.snapAngle = 15.0
|
||||
self.enable()
|
||||
|
||||
def enable(self):
|
||||
self.reparentTo(SEditor.group)
|
||||
self.updateGrid()
|
||||
self.fEnabled = 1
|
||||
|
||||
def disable(self):
|
||||
self.reparentTo(hidden)
|
||||
self.fEnabled = 0
|
||||
|
||||
def toggleGrid(self):
|
||||
if self.fEnabled:
|
||||
self.disable()
|
||||
else:
|
||||
self.enable()
|
||||
|
||||
def isEnabled(self):
|
||||
return self.fEnabled
|
||||
|
||||
def updateGrid(self):
|
||||
# Update grid lines based upon current grid spacing and grid size
|
||||
# First reset existing grid lines
|
||||
self.minorLines.reset()
|
||||
self.majorLines.reset()
|
||||
self.centerLines.reset()
|
||||
|
||||
# Now redraw lines
|
||||
numLines = int(math.ceil(self.gridSize/self.gridSpacing))
|
||||
scaledSize = numLines * self.gridSpacing
|
||||
|
||||
center = self.centerLines
|
||||
minor = self.minorLines
|
||||
major = self.majorLines
|
||||
for i in range(-numLines,numLines + 1):
|
||||
if i == 0:
|
||||
center.moveTo(i * self.gridSpacing, -scaledSize, 0)
|
||||
center.drawTo(i * self.gridSpacing, scaledSize, 0)
|
||||
center.moveTo(-scaledSize, i * self.gridSpacing, 0)
|
||||
center.drawTo(scaledSize, i * self.gridSpacing, 0)
|
||||
else:
|
||||
if (i % 5) == 0:
|
||||
major.moveTo(i * self.gridSpacing, -scaledSize, 0)
|
||||
major.drawTo(i * self.gridSpacing, scaledSize, 0)
|
||||
major.moveTo(-scaledSize, i * self.gridSpacing, 0)
|
||||
major.drawTo(scaledSize, i * self.gridSpacing, 0)
|
||||
else:
|
||||
minor.moveTo(i * self.gridSpacing, -scaledSize, 0)
|
||||
minor.drawTo(i * self.gridSpacing, scaledSize, 0)
|
||||
minor.moveTo(-scaledSize, i * self.gridSpacing, 0)
|
||||
minor.drawTo(scaledSize, i * self.gridSpacing, 0)
|
||||
|
||||
center.create()
|
||||
minor.create()
|
||||
major.create()
|
||||
self.gridBack.setScale(scaledSize)
|
||||
|
||||
def setXyzSnap(self, fSnap):
|
||||
self.fXyzSnap = fSnap
|
||||
|
||||
def getXyzSnap(self):
|
||||
return self.fXyzSnap
|
||||
|
||||
def setHprSnap(self, fSnap):
|
||||
self.fHprSnap = fSnap
|
||||
|
||||
def getHprSnap(self):
|
||||
return self.fHprSnap
|
||||
|
||||
def computeSnapPoint(self, point):
|
||||
# Start of with current point
|
||||
self.snapPos.assign(point)
|
||||
# Snap if necessary
|
||||
if self.fXyzSnap:
|
||||
self.snapPos.set(
|
||||
ROUND_TO(self.snapPos[0], self.gridSpacing),
|
||||
ROUND_TO(self.snapPos[1], self.gridSpacing),
|
||||
ROUND_TO(self.snapPos[2], self.gridSpacing))
|
||||
|
||||
# Move snap marker to this point
|
||||
self.snapMarker.setPos(self.snapPos)
|
||||
|
||||
# Return the hit point
|
||||
return self.snapPos
|
||||
|
||||
def computeSnapAngle(self, angle):
|
||||
return ROUND_TO(angle, self.snapAngle)
|
||||
|
||||
def setSnapAngle(self, angle):
|
||||
self.snapAngle = angle
|
||||
|
||||
def getSnapAngle(self):
|
||||
return self.snapAngle
|
||||
|
||||
def setGridSpacing(self, spacing):
|
||||
self.gridSpacing = spacing
|
||||
self.updateGrid()
|
||||
|
||||
def getGridSpacing(self):
|
||||
return self.gridSpacing
|
||||
|
||||
def setGridSize(self, size):
|
||||
# Set size of grid back and redraw lines
|
||||
self.gridSize = size
|
||||
self.updateGrid()
|
||||
|
||||
def getGridSize(self):
|
||||
return self.gridSize
|
633
build/nirai/panda3d/contrib/src/sceneeditor/seLights.py
Normal file
633
build/nirai/panda3d/contrib/src/sceneeditor/seLights.py
Normal file
|
@ -0,0 +1,633 @@
|
|||
#################################################################
|
||||
# seLights.py
|
||||
# Written by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#################################################################
|
||||
from direct.showbase.DirectObject import *
|
||||
from string import lower
|
||||
from direct.directtools import DirectUtil
|
||||
from pandac.PandaModules import *
|
||||
import string
|
||||
|
||||
|
||||
class seLight(NodePath):
|
||||
#################################################################
|
||||
# seLight(NodePath)
|
||||
# This is an object for keeping light data and let we can manipulate
|
||||
# lights as otherNopaths.
|
||||
# This idea basically is from directLight.
|
||||
# But the way directLight object worked is not we want in our
|
||||
# sceneEditor. So, we wrote one by ourself.
|
||||
#################################################################
|
||||
def __init__(self, light, parent, type,
|
||||
lightcolor=VBase4(0.3,0.3,0.3,1),
|
||||
specularColor = VBase4(1),
|
||||
position = Point3(0,0,0),
|
||||
orientation = Vec3(1,0,0),
|
||||
constant = 1.0,
|
||||
linear = 0.0,
|
||||
quadratic = 0.0,
|
||||
exponent = 0.0,
|
||||
tag="",
|
||||
lence = None):
|
||||
#################################################################
|
||||
# __init__(self, light, parent, type,
|
||||
# lightcolor=VBase4(0.3,0.3,0.3,1),
|
||||
# specularColor = VBase4(1),
|
||||
# position = Point3(0,0,0),
|
||||
# orientation = Vec3(1,0,0),
|
||||
# constant = 1.0,
|
||||
# linear = 0.0,
|
||||
# quadratic = 0.0,
|
||||
# exponent = 0.0,
|
||||
# tag="",
|
||||
# lence = None):
|
||||
# This constructor will create a light node inside it and upcast
|
||||
# this light node to itself as a nodePath.
|
||||
# Also, it will load a model as a reference to itself on the secene so that
|
||||
# user can easily recognize where is the light and can easily manipulate
|
||||
# by mouse picking and widget control.
|
||||
#################################################################
|
||||
# Initialize the super class
|
||||
NodePath.__init__(self)
|
||||
# Initialize and save values
|
||||
self.light = light
|
||||
self.type = type
|
||||
self.lightcolor=lightcolor
|
||||
self.specularColor = specularColor
|
||||
self.position = position
|
||||
self.orientation = orientation
|
||||
self.constant = constant
|
||||
self.linear = linear
|
||||
self.quadratic = quadratic
|
||||
self.exponent = exponent
|
||||
self.lence = lence
|
||||
self.active = True
|
||||
|
||||
if isinstance(light, Spotlight):
|
||||
node = light.upcastToLensNode()
|
||||
else:
|
||||
node = light.upcastToPandaNode()
|
||||
|
||||
# Attach node to self
|
||||
self.LightNode=parent.attachNewNode(node)
|
||||
self.LightNode.setTag("Metadata",tag)
|
||||
if(self.type=='spot'):
|
||||
self.LightNode.setHpr(self.orientation)
|
||||
self.LightNode.setPos(self.position)
|
||||
else:
|
||||
self.LightNode.setHpr(self.orientation)
|
||||
self.LightNode.setPos(self.position)
|
||||
|
||||
|
||||
self.assign(self.LightNode)
|
||||
if(self.type=='spot'):
|
||||
self.helpModel = loader.loadModel( "models/misc/Spotlight" )
|
||||
elif(self.type=='point'):
|
||||
self.helpModel = loader.loadModel( "models/misc/Pointlight" )
|
||||
elif(self.type=='directional'):
|
||||
self.helpModel = loader.loadModel( "models/misc/Dirlight" )
|
||||
else:
|
||||
self.helpModel = loader.loadModel( "models/misc/sphere" )
|
||||
self.helpModel.setColor(self.lightcolor)
|
||||
self.helpModel.reparentTo(self)
|
||||
DirectUtil.useDirectRenderStyle(self.helpModel)
|
||||
if not ((self.type == 'directional')or(self.type == 'point')or(self.type == 'spot')):
|
||||
self.helpModel.hide()
|
||||
|
||||
def getLight(self):
|
||||
#################################################################
|
||||
# getLight(self)
|
||||
# This function will return the light object it contains.
|
||||
#################################################################
|
||||
|
||||
return self.light
|
||||
|
||||
def getLightColor(self):
|
||||
#################################################################
|
||||
# getLightColor(self)
|
||||
# This function will return the color of the light color of this light node.
|
||||
#################################################################
|
||||
return self.lightcolor
|
||||
|
||||
def getName(self):
|
||||
#################################################################
|
||||
# getName(self)
|
||||
# This function will return the name of this light.
|
||||
#################################################################
|
||||
return self.light.getName()
|
||||
|
||||
def rename(self,name):
|
||||
#################################################################
|
||||
# rename(self, name)
|
||||
# User should specify a string object, name, as the new name of this
|
||||
# light node. This function will rename itself and light object
|
||||
# to this new name.
|
||||
#################################################################
|
||||
self.light.setName(name)
|
||||
self.setName(name)
|
||||
|
||||
def getType(self):
|
||||
#################################################################
|
||||
# getType(self)
|
||||
# This function will return a string which is the type of this
|
||||
# light node. (We only have four types of light)
|
||||
#################################################################
|
||||
return self.type
|
||||
|
||||
def setColor(self,color):
|
||||
#################################################################
|
||||
# setColor(self, color)
|
||||
# This function takes one input parameter, color, which is a
|
||||
# VBase4 object. This function will simply set this object into
|
||||
# light node it has to change the property of light.
|
||||
# Also, if the light type is either "directional" or "point", which
|
||||
# means it has a reference model with it, this function will also
|
||||
# change the reference model's color to input value.
|
||||
#################################################################
|
||||
self.light.setColor(color)
|
||||
self.lightcolor = color
|
||||
if (self.type == 'directional')or(self.type == 'point'):
|
||||
self.helpModel.setColor(self.lightcolor)
|
||||
return
|
||||
|
||||
def getSpecColor(self):
|
||||
#################################################################
|
||||
# getSpecColor(self)
|
||||
# This function will return the specular color of the light.
|
||||
# Although you can call this function for all kinds of light,
|
||||
# it will only meanful if this light is not a ambient light.
|
||||
#################################################################
|
||||
return self.specularColor
|
||||
|
||||
def setSpecColor(self,color):
|
||||
#################################################################
|
||||
# setSpecColor(self, color)
|
||||
# This function can be used to set the specular color of the light.
|
||||
# Although you can call this function for all kinds of light,
|
||||
# it will only meanful if the light type is not "ambient"
|
||||
#################################################################
|
||||
self.light.setSpecularColor(color)
|
||||
self.specularcolor = color
|
||||
return
|
||||
|
||||
def getPosition(self):
|
||||
#################################################################
|
||||
# getPosition(self)
|
||||
# getPosition(self)
|
||||
# This functioln will return a Point3 object which contains
|
||||
# the x, y, z position data of this light node.
|
||||
# It only has meaning for "point Light" and "Directional light"
|
||||
#################################################################
|
||||
self.position = self.LightNode.getPos()
|
||||
return self.position
|
||||
|
||||
def setPosition(self, pos):
|
||||
#################################################################
|
||||
# setPosition(self, pos)
|
||||
# This function will take a Point3 object as a input.
|
||||
# Then, this function will set the itself andd light node to the
|
||||
# target point.
|
||||
#################################################################
|
||||
self.LightNode.setPos(pos)
|
||||
self.position = pos
|
||||
return
|
||||
|
||||
def getOrientation(self):
|
||||
#################################################################
|
||||
# getOrientation(self)
|
||||
# This function will return a Vec3-type object which contains the
|
||||
# orientation data of this light node
|
||||
#
|
||||
# This function will only have meaning for point light and directional light.
|
||||
#
|
||||
#################################################################
|
||||
self.orientation = self.LightNode.getHpr()
|
||||
return self.orientation
|
||||
|
||||
def setOrientation(self,orient):
|
||||
#################################################################
|
||||
# setOrientation(self, orient)
|
||||
# This funtction will take a Vec3-type object as an input.
|
||||
# Then this function will set itself nad light node to face
|
||||
# the target orientation.
|
||||
#
|
||||
# This function only has meaning for point light and directional light
|
||||
# type of lights.
|
||||
#
|
||||
#################################################################
|
||||
self.LightNode.setHpr(orient)
|
||||
self.orientation = orient
|
||||
return
|
||||
|
||||
def getAttenuation(self):
|
||||
#################################################################
|
||||
# getAttenuation(self)
|
||||
# This function will return a Vec3 type of object which contains
|
||||
# the constant, linear and quadratic attenuation for this light node.
|
||||
#
|
||||
# This function will only have meaning for point light and spot light
|
||||
# tyoe of lights.
|
||||
#
|
||||
#################################################################
|
||||
return Vec3(self.constant,self.linear,self.quadratic)
|
||||
|
||||
def setConstantAttenuation(self, value):
|
||||
#################################################################
|
||||
# setConstantAttenuation(self, value)
|
||||
# This function will take a float number as an input.
|
||||
# Then, this function will set the Constant Atenuation value
|
||||
# to this number.
|
||||
#################################################################
|
||||
self.light.setAttenuation(Vec3(value, self.linear, self.quadratic))
|
||||
self.constant = value
|
||||
return
|
||||
|
||||
def setLinearAttenuation(self, value):
|
||||
#################################################################
|
||||
# setLinearAttenuation(self, value)
|
||||
# This function will take a float number as an input.
|
||||
# Then, this function will set the Linear Atenuation value
|
||||
# to this number.
|
||||
#################################################################
|
||||
self.light.setAttenuation(Vec3(self.constant, value, self.quadratic))
|
||||
self.linear = value
|
||||
return
|
||||
|
||||
def setQuadraticAttenuation(self, value):
|
||||
#################################################################
|
||||
# setQuadraticAttenuation(self, value)
|
||||
# This function will take a float number as an input.
|
||||
# Then, this function will set the Quadratic Atenuation value
|
||||
# to this number.
|
||||
#################################################################
|
||||
self.light.setAttenuation(Vec3(self.constant, self.linear, value))
|
||||
self.quadratic = value
|
||||
return
|
||||
|
||||
def getExponent(self):
|
||||
#################################################################
|
||||
# getExponent(self)
|
||||
# This function will return the value of the Exponent Attenuation
|
||||
# of this light node. (float)
|
||||
#################################################################
|
||||
return self.exponent
|
||||
|
||||
def setExponent(self, value):
|
||||
#################################################################
|
||||
# setExponent(self, value)
|
||||
# This function will take a float number as an input.
|
||||
# Then, this function will set the Exponent Atenuation value
|
||||
# to this number.
|
||||
#################################################################
|
||||
self.light.setExponent(value)
|
||||
self.exponent = value
|
||||
return
|
||||
|
||||
class seLightManager(NodePath):
|
||||
#################################################################
|
||||
# seLightManager(NodePath)
|
||||
# This is the class we used to control al lightings in our sceneEditor.
|
||||
#################################################################
|
||||
def __init__(self):
|
||||
# Initialize the superclass
|
||||
NodePath.__init__(self)
|
||||
# Create a node for the lights
|
||||
self.lnode=render.attachNewNode('Lights')
|
||||
self.assign(self.lnode)
|
||||
# Create a light attrib
|
||||
self.lightAttrib = LightAttrib.makeAllOff()
|
||||
self.lightDict = {}
|
||||
self.ambientCount = 0
|
||||
self.directionalCount = 0
|
||||
self.pointCount = 0
|
||||
self.spotCount = 0
|
||||
# Originally, we don't do this load model thing.
|
||||
# But the problem is, if we don't, then it will cause some
|
||||
# Bounding calculation error...
|
||||
self.helpModel = loader.loadModel( "models/misc/sphere" )
|
||||
self.helpModel.reparentTo(self)
|
||||
self.helpModel.hide()
|
||||
|
||||
|
||||
|
||||
|
||||
def create(self, type = 'ambient',
|
||||
lightcolor=VBase4(0.3,0.3,0.3,1),
|
||||
specularColor = VBase4(1),
|
||||
position = Point3(0,0,0),
|
||||
orientation = Vec3(1,0,0),
|
||||
constant = 1.0,
|
||||
linear = 0.0,
|
||||
quadratic = 0.0,
|
||||
exponent = 0.0,
|
||||
tag= "",
|
||||
name='DEFAULT_NAME'):
|
||||
#################################################################
|
||||
# create(self, type = 'ambient',
|
||||
# lightcolor=VBase4(0.3,0.3,0.3,1),
|
||||
# specularColor = VBase4(1),
|
||||
# position = Point3(0,0,0),
|
||||
# orientation = Vec3(1,0,0),
|
||||
# constant = 1.0,
|
||||
# linear = 0.0,
|
||||
# quadratic = 0.0,
|
||||
# exponent = 0.0,
|
||||
# tag= "",
|
||||
# name='DEFAULT_NAME')
|
||||
# As you can see, once user call this function and specify those
|
||||
# variables, this function will create a seLight node.
|
||||
# In the default, the light which just has been created will be
|
||||
# set to off.
|
||||
#################################################################
|
||||
### create the light
|
||||
|
||||
lence = None
|
||||
|
||||
if type == 'ambient':
|
||||
self.ambientCount += 1
|
||||
if(name=='DEFAULT_NAME'):
|
||||
light = AmbientLight('ambient_' + `self.ambientCount`)
|
||||
else:
|
||||
light = AmbientLight(name)
|
||||
|
||||
light.setColor(lightcolor)
|
||||
|
||||
elif type == 'directional':
|
||||
self.directionalCount += 1
|
||||
if(name=='DEFAULT_NAME'):
|
||||
light = DirectionalLight('directional_' + `self.directionalCount`)
|
||||
else:
|
||||
light = DirectionalLight(name)
|
||||
|
||||
light.setColor(lightcolor)
|
||||
light.setSpecularColor(specularColor)
|
||||
|
||||
elif type == 'point':
|
||||
self.pointCount += 1
|
||||
if(name=='DEFAULT_NAME'):
|
||||
light = PointLight('point_' + `self.pointCount`)
|
||||
else:
|
||||
light = PointLight(name)
|
||||
|
||||
light.setColor(lightcolor)
|
||||
light.setSpecularColor(specularColor)
|
||||
light.setAttenuation(Vec3(constant, linear, quadratic))
|
||||
|
||||
elif type == 'spot':
|
||||
self.spotCount += 1
|
||||
if(name=='DEFAULT_NAME'):
|
||||
light = Spotlight('spot_' + `self.spotCount`)
|
||||
else:
|
||||
light = Spotlight(name)
|
||||
|
||||
light.setColor(lightcolor)
|
||||
lence = PerspectiveLens()
|
||||
light.setLens(lence)
|
||||
light.setSpecularColor(specularColor)
|
||||
light.setAttenuation(Vec3(constant, linear, quadratic))
|
||||
light.setExponent(exponent)
|
||||
else:
|
||||
print 'Invalid light type'
|
||||
return None
|
||||
|
||||
# Create the seLight objects and put the light object we just created into it.
|
||||
lightNode = seLight(light,self,type,
|
||||
lightcolor=lightcolor,
|
||||
specularColor = specularColor,
|
||||
position = position,
|
||||
orientation = orientation,
|
||||
constant = constant,
|
||||
linear = linear,
|
||||
quadratic = quadratic,
|
||||
exponent = exponent,
|
||||
tag=tag,
|
||||
lence = lence
|
||||
)
|
||||
self.lightDict[light.getName()] = lightNode
|
||||
self.setOn(lightNode)
|
||||
|
||||
|
||||
return self.lightDict.keys(),lightNode
|
||||
|
||||
def addLight(self, light):
|
||||
#################################################################
|
||||
# addLight(self, light)
|
||||
# This function will put light in and save its properties in to a seLight Node
|
||||
# Attention!!
|
||||
# only Spotlight obj nneds to be specified a lens node first. i.e. setLens() first!
|
||||
#################################################################
|
||||
type = lower(light.getType().getName())
|
||||
|
||||
light.upcastToNamable()
|
||||
|
||||
specularColor = VBase4(1)
|
||||
position = Point3(0,0,0)
|
||||
orientation = Vec3(1,0,0)
|
||||
constant = 1.0
|
||||
linear = 0.0
|
||||
quadratic = 0.0
|
||||
exponent = 0.0
|
||||
lence = None
|
||||
|
||||
lightcolor = light.getColor()
|
||||
if type == 'ambientlight':
|
||||
type = 'ambient'
|
||||
self.ambientCount += 1
|
||||
elif type == 'directionallight':
|
||||
type = 'directional'
|
||||
self.directionalCount += 1
|
||||
orientation = light.getDirection()
|
||||
position = light.getPoint()
|
||||
specularColor = light.getSpecularColor()
|
||||
elif type == 'pointlight':
|
||||
type = 'point'
|
||||
self.pointCount += 1
|
||||
position = light.getPoint()
|
||||
specularColor = light.getSpecularColor()
|
||||
Attenuation = light.getAttenuation()
|
||||
constant = Attenuation.getX()
|
||||
linear = Attenuation.getY()
|
||||
quadratic = Attenuation.getZ()
|
||||
elif type == 'spotlight':
|
||||
type = 'spot'
|
||||
self.spotCount += 1
|
||||
specularColor = light.getSpecularColor()
|
||||
Attenuation = light.getAttenuation()
|
||||
constant = Attenuation.getX()
|
||||
linear = Attenuation.getY()
|
||||
quadratic = Attenuation.getZ()
|
||||
exponent = light.getExponent()
|
||||
else:
|
||||
print 'Invalid light type'
|
||||
return None
|
||||
|
||||
lightNode = seLight(light,self,type,
|
||||
lightcolor=lightcolor,
|
||||
specularColor = specularColor,
|
||||
position = position,
|
||||
orientation = orientation,
|
||||
constant = constant,
|
||||
linear = linear,
|
||||
quadratic = quadratic,
|
||||
exponent = exponent,
|
||||
lence = lence)
|
||||
self.lightDict[light.getName()] = lightNode
|
||||
self.setOn(lightNode)
|
||||
|
||||
return self.lightDict.keys(),lightNode
|
||||
|
||||
def delete(self, name, removeEntry = True):
|
||||
#################################################################
|
||||
# delete(self, name, removeEntry = True)
|
||||
# This function will remove light node had the same name with user input.
|
||||
# Also, you can specify the removeEntry to decide to remove the entry from the lightDict or not.
|
||||
# Normaly, you alway want to remove the entry from the dictionary. Thsi is only used for "deleteAll" function.
|
||||
#################################################################
|
||||
type = self.lightDict[name].getType()
|
||||
if type == 'ambient':
|
||||
self.ambientCount -= 1
|
||||
elif type == 'directional':
|
||||
self.directionalCount -= 1
|
||||
elif type == 'point':
|
||||
self.pointCount -= 1
|
||||
elif type == 'spot':
|
||||
self.spotCount -= 1
|
||||
self.setOff(self.lightDict[name])
|
||||
self.lightDict[name].removeChildren()
|
||||
self.lightDict[name].removeNode()
|
||||
if removeEntry:
|
||||
del self.lightDict[name]
|
||||
return self.lightDict.keys()
|
||||
|
||||
def deleteAll(self):
|
||||
#################################################################
|
||||
# deleteAll(self)
|
||||
# This function will keep calling delete and put exist lights in
|
||||
# until all lights have been eliminated.
|
||||
#################################################################
|
||||
for name in self.lightDict:
|
||||
self.delete(name, removeEntry = False)
|
||||
|
||||
self.lightDict.clear()
|
||||
|
||||
def isLight(self,name):
|
||||
#################################################################
|
||||
# isLight(self.name)
|
||||
# Use a string as a index to check if there existing a light named "name"
|
||||
#################################################################
|
||||
return self.lightDict.has_key(name)
|
||||
|
||||
def rename(self,oName,nName):
|
||||
#################################################################
|
||||
# rename(self, oName, nName)
|
||||
# This function will reanem the light named "oName(String)" to
|
||||
# nName(String)
|
||||
#################################################################
|
||||
if self.isLight(oName):
|
||||
lightNode = self.lightDict[oName]
|
||||
self.lightDict[nName] = lightNode
|
||||
lightNode.rename(nName)
|
||||
del self.lightDict[oName]
|
||||
return self.lightDict.keys(),lightNode
|
||||
else:
|
||||
print '----Light Mnager: No such Light!'
|
||||
|
||||
def getLightNodeList(self):
|
||||
#################################################################
|
||||
# getLightNodeList(self)
|
||||
# Return a list which contains all seLight nodes
|
||||
#################################################################
|
||||
list = []
|
||||
for name in self.lightDict:
|
||||
list.append(self.lightDict[name])
|
||||
return list
|
||||
|
||||
def getLightNodeDict(self):
|
||||
#################################################################
|
||||
# getLightNodeDict(self)
|
||||
# Return the light dictionary itself.
|
||||
#
|
||||
# Attention!
|
||||
# Because it doesn't make a copy when you return a dictionary, it
|
||||
# means when you can change the value from outside and that change
|
||||
# will directly reflect back to here.
|
||||
#
|
||||
#################################################################
|
||||
return self.lightDict
|
||||
|
||||
def getLightList(self):
|
||||
#################################################################
|
||||
# getLightList(self)
|
||||
# Return a list which contains names of all lights.
|
||||
#################################################################
|
||||
list = []
|
||||
for name in self.lightDict:
|
||||
list.append(name)
|
||||
return list
|
||||
|
||||
def getLightNode(self,lightName):
|
||||
#################################################################
|
||||
# getLightNode(self, lightName)
|
||||
# This function will return a seLight Node using a string, lightName. as a index.
|
||||
#################################################################
|
||||
if lightName in self.lightDict:
|
||||
return self.lightDict[lightName]
|
||||
|
||||
def allOn(self):
|
||||
#################################################################
|
||||
# allOb(self)
|
||||
# Enable the lighting system.
|
||||
#################################################################
|
||||
# Turn on all lighting
|
||||
render.node().setAttrib(self.lightAttrib)
|
||||
# Make sure there is a default material
|
||||
render.setMaterial(Material())
|
||||
|
||||
def allOff(self):
|
||||
#################################################################
|
||||
# allOff(self)
|
||||
# Disable whole lighting system
|
||||
#################################################################
|
||||
# Turn off all lighting
|
||||
render.node().clearAttrib(LightAttrib.getClassType())
|
||||
|
||||
def toggle(self):
|
||||
#################################################################
|
||||
# toggle(self)
|
||||
# Toggles light attribute, but doesn't toggle individual lights
|
||||
#################################################################
|
||||
if render.node().hasAttrib(LightAttrib.getClassType()):
|
||||
self.allOff()
|
||||
else:
|
||||
self.allOn()
|
||||
|
||||
def setOn(self, lightNode):
|
||||
#################################################################
|
||||
# setOn(lightNode)
|
||||
# This function will enable the input seLight node.
|
||||
# If the light system itself is down, activate it.
|
||||
#################################################################
|
||||
self.lightAttrib = self.lightAttrib.addLight(lightNode.getLight())
|
||||
lightNode.active = True
|
||||
if render.node().hasAttrib(LightAttrib.getClassType()):
|
||||
render.node().setAttrib(self.lightAttrib)
|
||||
|
||||
|
||||
def setOff(self, lightNode):
|
||||
#################################################################
|
||||
# setOff(self, lightNode)
|
||||
# This function will disable the input seLight node
|
||||
# If the light system itself is down, activate it.
|
||||
#################################################################
|
||||
lightNode.active = False
|
||||
self.lightAttrib = self.lightAttrib.removeLight(lightNode.getLight())
|
||||
if render.node().hasAttrib(LightAttrib.getClassType()):
|
||||
render.node().setAttrib(self.lightAttrib)
|
||||
|
||||
def getList(self):
|
||||
#################################################################
|
||||
# getList(self)
|
||||
# This function actually has the same functionality with getLightList(),
|
||||
# but this one should be more efficient.
|
||||
#################################################################
|
||||
return self.lightDict.keys()
|
956
build/nirai/panda3d/contrib/src/sceneeditor/seManipulation.py
Normal file
956
build/nirai/panda3d/contrib/src/sceneeditor/seManipulation.py
Normal file
|
@ -0,0 +1,956 @@
|
|||
#################################################################
|
||||
# seManipulation.py
|
||||
# Originally from DirectManipulation.py
|
||||
# Altered by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#
|
||||
# We didn't change anything essential.
|
||||
# Just because we customized the seSession from DirectSession,
|
||||
# So we need related files can follow the change.
|
||||
# However, we don't want to change anything inside the original directool
|
||||
# to let them can work with our scene editor.
|
||||
# (If we do change original directools, it will force user has to install the latest version of OUR Panda)
|
||||
#
|
||||
#################################################################
|
||||
|
||||
from direct.showbase.DirectObject import *
|
||||
from direct.directtools.DirectGlobals import *
|
||||
from direct.directtools.DirectUtil import *
|
||||
from seGeometry import *
|
||||
from direct.task import Task
|
||||
|
||||
class DirectManipulationControl(DirectObject):
|
||||
def __init__(self):
|
||||
# Create the grid
|
||||
self.objectHandles = ObjectHandles()
|
||||
self.hitPt = Point3(0)
|
||||
self.prevHit = Vec3(0)
|
||||
self.rotationCenter = Point3(0)
|
||||
self.initScaleMag = 1
|
||||
self.manipRef = SEditor.group.attachNewNode('manipRef')
|
||||
self.hitPtDist = 0
|
||||
self.constraint = None
|
||||
self.rotateAxis = 'x'
|
||||
self.lastCrankAngle = 0
|
||||
self.fSetCoa = 0
|
||||
self.fHitInit = 1
|
||||
self.fScaleInit = 1
|
||||
self.fWidgetTop = 0
|
||||
self.fFreeManip = 1
|
||||
self.fScaling = 0
|
||||
self.mode = None
|
||||
self.actionEvents = [
|
||||
['DIRECT-mouse1', self.manipulationStart],
|
||||
['DIRECT-mouse1Up', self.manipulationStop],
|
||||
['tab', self.toggleObjectHandlesMode],
|
||||
['.', self.objectHandles.multiplyScalingFactorBy, 2.0],
|
||||
['>', self.objectHandles.multiplyScalingFactorBy, 2.0],
|
||||
[',', self.objectHandles.multiplyScalingFactorBy, 0.5],
|
||||
['<', self.objectHandles.multiplyScalingFactorBy, 0.5],
|
||||
['shift-f', self.objectHandles.growToFit],
|
||||
['i', self.plantSelectedNodePath],
|
||||
]
|
||||
|
||||
def manipulationStart(self, modifiers):
|
||||
# Start out in select mode
|
||||
self.mode = 'select'
|
||||
# Check for a widget hit point
|
||||
entry = SEditor.iRay.pickWidget()
|
||||
# Did we hit a widget?
|
||||
if entry:
|
||||
# Yes!
|
||||
self.hitPt.assign(entry.getSurfacePoint(entry.getFromNodePath()))
|
||||
self.hitPtDist = Vec3(self.hitPt).length()
|
||||
# Constraint determined by nodes name
|
||||
self.constraint = entry.getIntoNodePath().getName()
|
||||
else:
|
||||
# Nope, off the widget, no constraint
|
||||
self.constraint = None
|
||||
# Check to see if we are moving the object
|
||||
# We are moving the object if we either wait long enough
|
||||
taskMgr.doMethodLater(MANIPULATION_MOVE_DELAY,
|
||||
self.switchToMoveMode,
|
||||
'manip-move-wait')
|
||||
# Or we move far enough
|
||||
self.moveDir = None
|
||||
watchMouseTask = Task.Task(self.watchMouseTask)
|
||||
watchMouseTask.initX = SEditor.dr.mouseX
|
||||
watchMouseTask.initY = SEditor.dr.mouseY
|
||||
taskMgr.add(watchMouseTask, 'manip-watch-mouse')
|
||||
|
||||
def switchToMoveMode(self, state):
|
||||
taskMgr.remove('manip-watch-mouse')
|
||||
self.mode = 'move'
|
||||
self.manipulateObject()
|
||||
return Task.done
|
||||
|
||||
def watchMouseTask(self, state):
|
||||
if (((abs (state.initX - SEditor.dr.mouseX)) > 0.01) or
|
||||
((abs (state.initY - SEditor.dr.mouseY)) > 0.01)):
|
||||
taskMgr.remove('manip-move-wait')
|
||||
self.mode = 'move'
|
||||
self.manipulateObject()
|
||||
return Task.done
|
||||
else:
|
||||
return Task.cont
|
||||
|
||||
def manipulationStop(self,xy=[]):
|
||||
taskMgr.remove('manipulateObject')
|
||||
taskMgr.remove('manip-move-wait')
|
||||
taskMgr.remove('manip-watch-mouse')
|
||||
# depending on flag.....
|
||||
if self.mode == 'select':
|
||||
# Check for object under mouse
|
||||
# Don't intersect with hidden or backfacing objects
|
||||
skipFlags = SKIP_HIDDEN | SKIP_BACKFACE
|
||||
# Skip camera (and its children), unless control key is pressed
|
||||
skipFlags |= SKIP_CAMERA * (1 - base.getControl())
|
||||
entry = SEditor.iRay.pickGeom(skipFlags = skipFlags)
|
||||
if entry:
|
||||
# Record hit point information
|
||||
self.hitPt.assign(entry.getSurfacePoint(entry.getFromNodePath()))
|
||||
self.hitPtDist = Vec3(self.hitPt).length()
|
||||
# Select it
|
||||
SEditor.select(entry.getIntoNodePath(), SEditor.fShift)
|
||||
else:
|
||||
SEditor.deselectAll()
|
||||
else:
|
||||
self.manipulateObjectCleanup()
|
||||
|
||||
def manipulateObjectCleanup(self):
|
||||
if self.fScaling:
|
||||
# We had been scaling, need to reset object handles
|
||||
self.objectHandles.transferObjectHandlesScale()
|
||||
self.fScaling = 0
|
||||
SEditor.selected.highlightAll()
|
||||
self.objectHandles.showAllHandles()
|
||||
self.objectHandles.hideGuides()
|
||||
# Restart followSelectedNodePath task
|
||||
self.spawnFollowSelectedNodePathTask()
|
||||
messenger.send('DIRECT_manipulateObjectCleanup')
|
||||
|
||||
def spawnFollowSelectedNodePathTask(self):
|
||||
# If nothing selected, just return
|
||||
if not SEditor.selected.last:
|
||||
return
|
||||
# Clear out old task to make sure
|
||||
taskMgr.remove('followSelectedNodePath')
|
||||
# Where are the object handles relative to the selected object
|
||||
pos = VBase3(0)
|
||||
hpr = VBase3(0)
|
||||
decomposeMatrix(SEditor.selected.last.mCoa2Dnp,
|
||||
VBase3(0), hpr, pos, CSDefault)
|
||||
# Create the task
|
||||
t = Task.Task(self.followSelectedNodePathTask)
|
||||
# Update state variables
|
||||
t.pos = pos
|
||||
t.hpr = hpr
|
||||
t.base = SEditor.selected.last
|
||||
# Spawn the task
|
||||
taskMgr.add(t, 'followSelectedNodePath')
|
||||
|
||||
def followSelectedNodePathTask(self, state):
|
||||
SEditor.widget.setPosHpr(state.base, state.pos, state.hpr)
|
||||
return Task.cont
|
||||
|
||||
def enableManipulation(self):
|
||||
# Accept events
|
||||
for event in self.actionEvents:
|
||||
self.accept(event[0], event[1], extraArgs = event[2:])
|
||||
|
||||
def disableManipulation(self):
|
||||
# Ignore events
|
||||
for event in self.actionEvents:
|
||||
self.ignore(event[0])
|
||||
self.removeManipulateObjectTask()
|
||||
taskMgr.remove('manipulateObject')
|
||||
taskMgr.remove('manip-move-wait')
|
||||
taskMgr.remove('manip-watch-mouse')
|
||||
taskMgr.remove('highlightWidgetTask')
|
||||
taskMgr.remove('resizeObjectHandles')
|
||||
|
||||
def toggleObjectHandlesMode(self):
|
||||
self.fSetCoa = 1 - self.fSetCoa
|
||||
if self.fSetCoa:
|
||||
self.objectHandles.coaModeColor()
|
||||
else:
|
||||
self.objectHandles.manipModeColor()
|
||||
|
||||
def removeManipulateObjectTask(self):
|
||||
taskMgr.remove('manipulateObject')
|
||||
|
||||
def manipulateObject(self):
|
||||
# Only do this if something is selected
|
||||
if SEditor.selected:
|
||||
# Remove the task to keep the widget attached to the object
|
||||
taskMgr.remove('followSelectedNodePath')
|
||||
# and the task to highlight the widget
|
||||
taskMgr.remove('highlightWidgetTask')
|
||||
# Set manipulation flag
|
||||
self.fManip = 1
|
||||
# Record undo point
|
||||
SEditor.pushUndo(SEditor.selected)
|
||||
# Update object handles visibility
|
||||
self.objectHandles.showGuides()
|
||||
self.objectHandles.hideAllHandles()
|
||||
self.objectHandles.showHandle(self.constraint)
|
||||
# Record relationship between selected nodes and widget
|
||||
SEditor.selected.getWrtAll()
|
||||
# hide the bbox of the selected objects during interaction
|
||||
SEditor.selected.dehighlightAll()
|
||||
# Send event to signal start of manipulation
|
||||
messenger.send('DIRECT_manipulateObjectStart')
|
||||
# Manipulate the real object with the constraint
|
||||
# The constraint is passed as the name of the node
|
||||
self.spawnManipulateObjectTask()
|
||||
|
||||
def spawnManipulateObjectTask(self):
|
||||
# reset hit-pt flag
|
||||
self.fHitInit = 1
|
||||
self.fScaleInit = 1
|
||||
# record initial offset between widget and camera
|
||||
t = Task.Task(self.manipulateObjectTask)
|
||||
t.fMouseX = abs(SEditor.dr.mouseX) > 0.9
|
||||
t.fMouseY = abs(SEditor.dr.mouseY) > 0.9
|
||||
if t.fMouseX:
|
||||
t.constrainedDir = 'y'
|
||||
else:
|
||||
t.constrainedDir = 'x'
|
||||
# Compute widget's xy coords in screen space
|
||||
t.coaCenter = getScreenXY(SEditor.widget)
|
||||
# These are used to rotate about view vector
|
||||
if t.fMouseX and t.fMouseY:
|
||||
t.lastAngle = getCrankAngle(t.coaCenter)
|
||||
taskMgr.add(t, 'manipulateObject')
|
||||
|
||||
def manipulateObjectTask(self, state):
|
||||
# Widget takes precedence
|
||||
if self.constraint:
|
||||
type = self.constraint[2:]
|
||||
if type == 'post':
|
||||
self.xlate1D(state)
|
||||
elif type == 'disc':
|
||||
self.xlate2D(state)
|
||||
elif type == 'ring':
|
||||
self.rotate1D(state)
|
||||
# No widget interaction, determine free manip mode
|
||||
elif self.fFreeManip:
|
||||
# If we've been scaling and changed modes, reset object handles
|
||||
if 0 and self.fScaling and (not SEditor.fAlt):
|
||||
self.objectHandles.transferObjectHandlesScale()
|
||||
self.fScaling = 0
|
||||
# Alt key switches to a scaling mode
|
||||
if SEditor.fControl:
|
||||
self.fScaling = 1
|
||||
self.scale3D(state)
|
||||
# Otherwise, manip mode depends on where you started
|
||||
elif state.fMouseX and state.fMouseY:
|
||||
# In the corner, spin around camera's axis
|
||||
self.rotateAboutViewVector(state)
|
||||
elif state.fMouseX or state.fMouseY:
|
||||
# Mouse started elsewhere in the outer frame, rotate
|
||||
self.rotate2D(state)
|
||||
else:
|
||||
# Mouse started in central region, xlate
|
||||
# Mode depends on shift key
|
||||
if SEditor.fShift or SEditor.fControl:
|
||||
self.xlateCamXY(state)
|
||||
else:
|
||||
self.xlateCamXZ(state)
|
||||
if self.fSetCoa:
|
||||
# Update coa based on current widget position
|
||||
SEditor.selected.last.mCoa2Dnp.assign(
|
||||
SEditor.widget.getMat(SEditor.selected.last))
|
||||
else:
|
||||
# Move the objects with the widget
|
||||
SEditor.selected.moveWrtWidgetAll()
|
||||
# Continue
|
||||
return Task.cont
|
||||
|
||||
### WIDGET MANIPULATION METHODS ###
|
||||
def xlate1D(self, state):
|
||||
# Constrained 1D Translation along widget axis
|
||||
# Compute nearest hit point along axis and try to keep
|
||||
# that point as close to the current mouse position as possible
|
||||
# what point on the axis is the mouse pointing at?
|
||||
self.hitPt.assign(self.objectHandles.getAxisIntersectPt(
|
||||
self.constraint[:1]))
|
||||
# use it to see how far to move the widget
|
||||
if self.fHitInit:
|
||||
# First time through, just record that point
|
||||
self.fHitInit = 0
|
||||
self.prevHit.assign(self.hitPt)
|
||||
else:
|
||||
# Move widget to keep hit point as close to mouse as possible
|
||||
offset = self.hitPt - self.prevHit
|
||||
SEditor.widget.setPos(SEditor.widget, offset)
|
||||
|
||||
def xlate2D(self, state):
|
||||
# Constrained 2D (planar) translation
|
||||
# Compute point of intersection of ray from eyepoint through cursor
|
||||
# to one of the three orthogonal planes on the widget.
|
||||
# This point tracks all subsequent mouse movements
|
||||
self.hitPt.assign(self.objectHandles.getWidgetIntersectPt(
|
||||
SEditor.widget, self.constraint[:1]))
|
||||
# use it to see how far to move the widget
|
||||
if self.fHitInit:
|
||||
# First time through just record hit point
|
||||
self.fHitInit = 0
|
||||
self.prevHit.assign(self.hitPt)
|
||||
else:
|
||||
offset = self.hitPt - self.prevHit
|
||||
SEditor.widget.setPos(SEditor.widget, offset)
|
||||
|
||||
def rotate1D(self, state):
|
||||
# Constrained 1D rotation about the widget's main axis (X,Y, or Z)
|
||||
# Rotation depends upon circular motion of the mouse about the
|
||||
# projection of the widget's origin on the image plane
|
||||
# A complete circle about the widget results in a change in
|
||||
# orientation of 360 degrees.
|
||||
|
||||
# First initialize hit point/rotation angle
|
||||
if self.fHitInit:
|
||||
self.fHitInit = 0
|
||||
self.rotateAxis = self.constraint[:1]
|
||||
self.fWidgetTop = self.widgetCheck('top?')
|
||||
self.rotationCenter = getScreenXY(SEditor.widget)
|
||||
self.lastCrankAngle = getCrankAngle(self.rotationCenter)
|
||||
|
||||
# Rotate widget based on how far cursor has swung around origin
|
||||
newAngle = getCrankAngle(self.rotationCenter)
|
||||
deltaAngle = self.lastCrankAngle - newAngle
|
||||
if self.fWidgetTop:
|
||||
deltaAngle = -1 * deltaAngle
|
||||
if self.rotateAxis == 'x':
|
||||
SEditor.widget.setP(SEditor.widget, deltaAngle)
|
||||
elif self.rotateAxis == 'y':
|
||||
if base.config.GetBool('temp-hpr-fix',0):
|
||||
SEditor.widget.setR(SEditor.widget, deltaAngle)
|
||||
else:
|
||||
SEditor.widget.setR(SEditor.widget, -deltaAngle)
|
||||
elif self.rotateAxis == 'z':
|
||||
SEditor.widget.setH(SEditor.widget, deltaAngle)
|
||||
# Record crank angle for next time around
|
||||
self.lastCrankAngle = newAngle
|
||||
|
||||
def widgetCheck(self,type):
|
||||
# Utility to see if we are looking at the top or bottom of
|
||||
# a 2D planar widget or if we are looking at a 2D planar widget
|
||||
# edge on
|
||||
# Based upon angle between view vector from eye through the
|
||||
# widget's origin and one of the three principle axes
|
||||
axis = self.constraint[:1]
|
||||
# First compute vector from eye through widget origin
|
||||
mWidget2Cam = SEditor.widget.getMat(SEditor.camera)
|
||||
# And determine where the viewpoint is relative to widget
|
||||
pos = VBase3(0)
|
||||
decomposeMatrix(mWidget2Cam, VBase3(0), VBase3(0), pos,
|
||||
CSDefault)
|
||||
widgetDir = Vec3(pos)
|
||||
widgetDir.normalize()
|
||||
# Convert specified widget axis to view space
|
||||
if axis == 'x':
|
||||
widgetAxis = Vec3(mWidget2Cam.xformVec(X_AXIS))
|
||||
elif axis == 'y':
|
||||
widgetAxis = Vec3(mWidget2Cam.xformVec(Y_AXIS))
|
||||
elif axis == 'z':
|
||||
widgetAxis = Vec3(mWidget2Cam.xformVec(Z_AXIS))
|
||||
widgetAxis.normalize()
|
||||
if type == 'top?':
|
||||
# Check sign of angle between two vectors
|
||||
return (widgetDir.dot(widgetAxis) < 0.)
|
||||
elif type == 'edge?':
|
||||
# Checking to see if we are viewing edge-on
|
||||
# Check angle between two vectors
|
||||
return(abs(widgetDir.dot(widgetAxis)) < .2)
|
||||
|
||||
### FREE MANIPULATION METHODS ###
|
||||
def xlateCamXZ(self, state):
|
||||
"""Constrained 2D motion parallel to the camera's image plane
|
||||
This moves the object in the camera's XZ plane"""
|
||||
# reset fHitInit in case we later switch to manip mode
|
||||
self.fHitInit = 1
|
||||
# Reset scaling init flag
|
||||
self.fScaleInit = 1
|
||||
# Where is the widget relative to current camera view
|
||||
vWidget2Camera = SEditor.widget.getPos(SEditor.camera)
|
||||
x = vWidget2Camera[0]
|
||||
y = vWidget2Camera[1]
|
||||
z = vWidget2Camera[2]
|
||||
# Move widget (and objects) based upon mouse motion
|
||||
# Scaled up accordingly based upon widget distance
|
||||
dr = SEditor.dr
|
||||
SEditor.widget.setX(
|
||||
SEditor.camera,
|
||||
x + 0.5 * dr.mouseDeltaX * dr.nearWidth * (y/dr.near))
|
||||
SEditor.widget.setZ(
|
||||
SEditor.camera,
|
||||
z + 0.5 * dr.mouseDeltaY * dr.nearHeight * (y/dr.near))
|
||||
|
||||
def xlateCamXY(self, state):
|
||||
"""Constrained 2D motion perpendicular to camera's image plane
|
||||
This moves the object in the camera's XY plane if shift is held
|
||||
Moves object toward camera if control is held
|
||||
"""
|
||||
# Reset scaling init flag
|
||||
self.fScaleInit = 1
|
||||
# Now, where is the widget relative to current camera view
|
||||
vWidget2Camera = SEditor.widget.getPos(SEditor.camera)
|
||||
# If this is first time around, record initial y distance
|
||||
if self.fHitInit:
|
||||
self.fHitInit = 0
|
||||
# Use distance to widget to scale motion along Y
|
||||
self.xlateSF = Vec3(vWidget2Camera).length()
|
||||
# Get widget's current xy coords in screen space
|
||||
coaCenter = getNearProjectionPoint(SEditor.widget)
|
||||
self.deltaNearX = coaCenter[0] - SEditor.dr.nearVec[0]
|
||||
# Which way do we move the object?
|
||||
if SEditor.fControl:
|
||||
moveDir = Vec3(vWidget2Camera)
|
||||
# If widget is behind camera invert vector
|
||||
if moveDir[1] < 0.0:
|
||||
moveDir.assign(moveDir * -1)
|
||||
moveDir.normalize()
|
||||
else:
|
||||
moveDir = Vec3(Y_AXIS)
|
||||
# Move selected objects
|
||||
dr = SEditor.dr
|
||||
# Scale move dir
|
||||
moveDir.assign(moveDir * (2.0 * dr.mouseDeltaY * self.xlateSF))
|
||||
# Add it to current widget offset
|
||||
vWidget2Camera += moveDir
|
||||
# The object, however, stays at the same relative point to mouse in X
|
||||
vWidget2Camera.setX((dr.nearVec[0] + self.deltaNearX) *
|
||||
(vWidget2Camera[1]/dr.near))
|
||||
# Move widget
|
||||
SEditor.widget.setPos(SEditor.camera, vWidget2Camera)
|
||||
|
||||
def rotate2D(self, state):
|
||||
""" Virtual trackball rotation of widget """
|
||||
# Reset init flag in case we switch to another mode
|
||||
self.fHitInit = 1
|
||||
# Reset scaling init flag
|
||||
self.fScaleInit = 1
|
||||
tumbleRate = 360
|
||||
# If moving outside of center, ignore motion perpendicular to edge
|
||||
if ((state.constrainedDir == 'y') and (abs(SEditor.dr.mouseX) > 0.9)):
|
||||
deltaX = 0
|
||||
deltaY = SEditor.dr.mouseDeltaY
|
||||
elif ((state.constrainedDir == 'x') and (abs(SEditor.dr.mouseY) > 0.9)):
|
||||
deltaX = SEditor.dr.mouseDeltaX
|
||||
deltaY = 0
|
||||
else:
|
||||
deltaX = SEditor.dr.mouseDeltaX
|
||||
deltaY = SEditor.dr.mouseDeltaY
|
||||
# Mouse motion edge to edge of display region results in one full turn
|
||||
relHpr(SEditor.widget, SEditor.camera, deltaX * tumbleRate,
|
||||
-deltaY * tumbleRate, 0)
|
||||
|
||||
def rotateAboutViewVector(self, state):
|
||||
# Reset init flag in case we switch to another mode
|
||||
self.fHitInit = 1
|
||||
# Reset scaling init flag
|
||||
self.fScaleInit = 1
|
||||
# Compute current angle
|
||||
angle = getCrankAngle(state.coaCenter)
|
||||
deltaAngle = angle - state.lastAngle
|
||||
state.lastAngle = angle
|
||||
# Mouse motion edge to edge of display region results in one full turn
|
||||
if base.config.GetBool('temp-hpr-fix',0):
|
||||
relHpr(SEditor.widget, SEditor.camera, 0, 0, -deltaAngle)
|
||||
else:
|
||||
relHpr(SEditor.widget, SEditor.camera, 0, 0, deltaAngle)
|
||||
|
||||
def scale3D(self, state):
|
||||
# Scale the selected node based upon up down mouse motion
|
||||
# Mouse motion from edge to edge results in a factor of 4 scaling
|
||||
# From midpoint to edge doubles or halves objects scale
|
||||
if self.fScaleInit:
|
||||
self.fScaleInit = 0
|
||||
self.manipRef.setPos(SEditor.widget, 0, 0, 0)
|
||||
self.manipRef.setHpr(SEditor.camera, 0, 0, 0)
|
||||
self.initScaleMag = Vec3(
|
||||
self.objectHandles.getWidgetIntersectPt(
|
||||
self.manipRef, 'y')).length()
|
||||
# record initial scale
|
||||
self.initScale = SEditor.widget.getScale()
|
||||
# Reset fHitInitFlag
|
||||
self.fHitInit = 1
|
||||
# Begin
|
||||
# Scale factor is ratio current mag with init mag
|
||||
currScale = (
|
||||
self.initScale *
|
||||
(self.objectHandles.getWidgetIntersectPt(
|
||||
self.manipRef, 'y').length() /
|
||||
self.initScaleMag)
|
||||
)
|
||||
SEditor.widget.setScale(currScale)
|
||||
|
||||
## Utility functions ##
|
||||
def plantSelectedNodePath(self):
|
||||
""" Move selected object to intersection point of cursor on scene """
|
||||
# Check for intersection
|
||||
entry = SEditor.iRay.pickGeom(
|
||||
skipFlags = SKIP_HIDDEN | SKIP_BACKFACE | SKIP_CAMERA)
|
||||
# MRM: Need to handle moving COA
|
||||
if (entry != None) and (SEditor.selected.last != None):
|
||||
# Record undo point
|
||||
SEditor.pushUndo(SEditor.selected)
|
||||
# Record wrt matrix
|
||||
SEditor.selected.getWrtAll()
|
||||
# Move selected
|
||||
SEditor.widget.setPos(
|
||||
SEditor.camera,entry.getSurfacePoint(entry.getFromNodePath()))
|
||||
# Move all the selected objects with widget
|
||||
# Move the objects with the widget
|
||||
SEditor.selected.moveWrtWidgetAll()
|
||||
# Let everyone know that something was moved
|
||||
messenger.send('DIRECT_manipulateObjectCleanup')
|
||||
|
||||
class ObjectHandles(NodePath,DirectObject):
|
||||
def __init__(self):
|
||||
# Initialize the superclass
|
||||
NodePath.__init__(self)
|
||||
|
||||
# Load up object handles model and assign it to self
|
||||
self.assign(loader.loadModel('models/misc/objectHandles'))
|
||||
self.setName('objectHandles')
|
||||
self.scalingNode = self.getChild(0)
|
||||
self.scalingNode.setName('ohScalingNode')
|
||||
self.ohScalingFactor = 1.0
|
||||
# To avoid recreating a vec every frame
|
||||
self.hitPt = Vec3(0)
|
||||
# Get a handle on the components
|
||||
self.xHandles = self.find('**/X')
|
||||
self.xPostGroup = self.xHandles.find('**/x-post-group')
|
||||
self.xPostCollision = self.xHandles.find('**/x-post')
|
||||
self.xRingGroup = self.xHandles.find('**/x-ring-group')
|
||||
self.xRingCollision = self.xHandles.find('**/x-ring')
|
||||
self.xDiscGroup = self.xHandles.find('**/x-disc-group')
|
||||
self.xDisc = self.xHandles.find('**/x-disc-visible')
|
||||
self.xDiscCollision = self.xHandles.find('**/x-disc')
|
||||
|
||||
self.yHandles = self.find('**/Y')
|
||||
self.yPostGroup = self.yHandles.find('**/y-post-group')
|
||||
self.yPostCollision = self.yHandles.find('**/y-post')
|
||||
self.yRingGroup = self.yHandles.find('**/y-ring-group')
|
||||
self.yRingCollision = self.yHandles.find('**/y-ring')
|
||||
self.yDiscGroup = self.yHandles.find('**/y-disc-group')
|
||||
self.yDisc = self.yHandles.find('**/y-disc-visible')
|
||||
self.yDiscCollision = self.yHandles.find('**/y-disc')
|
||||
|
||||
self.zHandles = self.find('**/Z')
|
||||
self.zPostGroup = self.zHandles.find('**/z-post-group')
|
||||
self.zPostCollision = self.zHandles.find('**/z-post')
|
||||
self.zRingGroup = self.zHandles.find('**/z-ring-group')
|
||||
self.zRingCollision = self.zHandles.find('**/z-ring')
|
||||
self.zDiscGroup = self.zHandles.find('**/z-disc-group')
|
||||
self.zDisc = self.zHandles.find('**/z-disc-visible')
|
||||
self.zDiscCollision = self.zHandles.find('**/z-disc')
|
||||
|
||||
# Adjust visiblity, colors, and transparency
|
||||
self.xPostCollision.hide()
|
||||
self.xRingCollision.hide()
|
||||
self.xDisc.setColor(1,0,0,.2)
|
||||
self.yPostCollision.hide()
|
||||
self.yRingCollision.hide()
|
||||
self.yDisc.setColor(0,1,0,.2)
|
||||
self.zPostCollision.hide()
|
||||
self.zRingCollision.hide()
|
||||
self.zDisc.setColor(0,0,1,.2)
|
||||
# Augment geometry with lines
|
||||
self.createObjectHandleLines()
|
||||
# Create long markers to help line up in world
|
||||
self.createGuideLines()
|
||||
self.hideGuides()
|
||||
|
||||
# Start with widget handles hidden
|
||||
self.fActive = 1
|
||||
self.toggleWidget()
|
||||
|
||||
# Make sure object handles are never lit or drawn in wireframe
|
||||
useDirectRenderStyle(self)
|
||||
|
||||
def coaModeColor(self):
|
||||
self.setColor(.5,.5,.5,1)
|
||||
|
||||
def manipModeColor(self):
|
||||
self.clearColor()
|
||||
|
||||
def toggleWidget(self):
|
||||
if self.fActive:
|
||||
self.deactivate()
|
||||
else:
|
||||
self.activate()
|
||||
|
||||
def activate(self):
|
||||
self.scalingNode.reparentTo(self)
|
||||
self.fActive = 1
|
||||
|
||||
def deactivate(self):
|
||||
self.scalingNode.reparentTo(hidden)
|
||||
self.fActive = 0
|
||||
|
||||
def showWidgetIfActive(self):
|
||||
if self.fActive:
|
||||
self.reparentTo(SEditor.group)
|
||||
|
||||
def showWidget(self):
|
||||
self.reparentTo(SEditor.group)
|
||||
|
||||
def hideWidget(self):
|
||||
self.reparentTo(hidden)
|
||||
|
||||
def enableHandles(self, handles):
|
||||
if type(handles) == types.ListType:
|
||||
for handle in handles:
|
||||
self.enableHandle(handle)
|
||||
elif handles == 'x':
|
||||
self.enableHandles(['x-post','x-ring','x-disc'])
|
||||
elif handles == 'y':
|
||||
self.enableHandles(['y-post','y-ring','y-disc'])
|
||||
elif handles == 'z':
|
||||
self.enableHandles(['z-post','z-ring','z-disc'])
|
||||
elif handles == 'post':
|
||||
self.enableHandles(['x-post','y-post','z-post'])
|
||||
elif handles == 'ring':
|
||||
self.enableHandles(['x-ring','y-ring','z-ring'])
|
||||
elif handles == 'disc':
|
||||
self.enableHandles(['x-disc','y-disc','z-disc'])
|
||||
elif handles == 'all':
|
||||
self.enableHandles(['x-post','x-ring','x-disc',
|
||||
'y-post','y-ring','y-disc',
|
||||
'z-post','z-ring','z-disc'])
|
||||
|
||||
def enableHandle(self, handle):
|
||||
if handle == 'x-post':
|
||||
self.xPostGroup.reparentTo(self.xHandles)
|
||||
elif handle == 'x-ring':
|
||||
self.xRingGroup.reparentTo(self.xHandles)
|
||||
elif handle == 'x-disc':
|
||||
self.xDiscGroup.reparentTo(self.xHandles)
|
||||
if handle == 'y-post':
|
||||
self.yPostGroup.reparentTo(self.yHandles)
|
||||
elif handle == 'y-ring':
|
||||
self.yRingGroup.reparentTo(self.yHandles)
|
||||
elif handle == 'y-disc':
|
||||
self.yDiscGroup.reparentTo(self.yHandles)
|
||||
if handle == 'z-post':
|
||||
self.zPostGroup.reparentTo(self.zHandles)
|
||||
elif handle == 'z-ring':
|
||||
self.zRingGroup.reparentTo(self.zHandles)
|
||||
elif handle == 'z-disc':
|
||||
self.zDiscGroup.reparentTo(self.zHandles)
|
||||
|
||||
def disableHandles(self, handles):
|
||||
if type(handles) == types.ListType:
|
||||
for handle in handles:
|
||||
self.disableHandle(handle)
|
||||
elif handles == 'x':
|
||||
self.disableHandles(['x-post','x-ring','x-disc'])
|
||||
elif handles == 'y':
|
||||
self.disableHandles(['y-post','y-ring','y-disc'])
|
||||
elif handles == 'z':
|
||||
self.disableHandles(['z-post','z-ring','z-disc'])
|
||||
elif handles == 'post':
|
||||
self.disableHandles(['x-post','y-post','z-post'])
|
||||
elif handles == 'ring':
|
||||
self.disableHandles(['x-ring','y-ring','z-ring'])
|
||||
elif handles == 'disc':
|
||||
self.disableHandles(['x-disc','y-disc','z-disc'])
|
||||
elif handles == 'all':
|
||||
self.disableHandles(['x-post','x-ring','x-disc',
|
||||
'y-post','y-ring','y-disc',
|
||||
'z-post','z-ring','z-disc'])
|
||||
|
||||
def disableHandle(self, handle):
|
||||
if handle == 'x-post':
|
||||
self.xPostGroup.reparentTo(hidden)
|
||||
elif handle == 'x-ring':
|
||||
self.xRingGroup.reparentTo(hidden)
|
||||
elif handle == 'x-disc':
|
||||
self.xDiscGroup.reparentTo(hidden)
|
||||
if handle == 'y-post':
|
||||
self.yPostGroup.reparentTo(hidden)
|
||||
elif handle == 'y-ring':
|
||||
self.yRingGroup.reparentTo(hidden)
|
||||
elif handle == 'y-disc':
|
||||
self.yDiscGroup.reparentTo(hidden)
|
||||
if handle == 'z-post':
|
||||
self.zPostGroup.reparentTo(hidden)
|
||||
elif handle == 'z-ring':
|
||||
self.zRingGroup.reparentTo(hidden)
|
||||
elif handle == 'z-disc':
|
||||
self.zDiscGroup.reparentTo(hidden)
|
||||
|
||||
def showAllHandles(self):
|
||||
self.xPost.show()
|
||||
self.xRing.show()
|
||||
self.xDisc.show()
|
||||
self.yPost.show()
|
||||
self.yRing.show()
|
||||
self.yDisc.show()
|
||||
self.zPost.show()
|
||||
self.zRing.show()
|
||||
self.zDisc.show()
|
||||
|
||||
def hideAllHandles(self):
|
||||
self.xPost.hide()
|
||||
self.xRing.hide()
|
||||
self.xDisc.hide()
|
||||
self.yPost.hide()
|
||||
self.yRing.hide()
|
||||
self.yDisc.hide()
|
||||
self.zPost.hide()
|
||||
self.zRing.hide()
|
||||
self.zDisc.hide()
|
||||
|
||||
def showHandle(self, handle):
|
||||
if handle == 'x-post':
|
||||
self.xPost.show()
|
||||
elif handle == 'x-ring':
|
||||
self.xRing.show()
|
||||
elif handle == 'x-disc':
|
||||
self.xDisc.show()
|
||||
elif handle == 'y-post':
|
||||
self.yPost.show()
|
||||
elif handle == 'y-ring':
|
||||
self.yRing.show()
|
||||
elif handle == 'y-disc':
|
||||
self.yDisc.show()
|
||||
elif handle == 'z-post':
|
||||
self.zPost.show()
|
||||
elif handle == 'z-ring':
|
||||
self.zRing.show()
|
||||
elif handle == 'z-disc':
|
||||
self.zDisc.show()
|
||||
|
||||
def showGuides(self):
|
||||
self.guideLines.show()
|
||||
|
||||
def hideGuides(self):
|
||||
self.guideLines.hide()
|
||||
|
||||
def setScalingFactor(self, scaleFactor):
|
||||
self.ohScalingFactor = scaleFactor
|
||||
self.scalingNode.setScale(self.ohScalingFactor)
|
||||
|
||||
def getScalingFactor(self):
|
||||
return self.scalingNode.getScale()
|
||||
|
||||
def transferObjectHandlesScale(self):
|
||||
# see how much object handles have been scaled
|
||||
ohs = self.getScale()
|
||||
sns = self.scalingNode.getScale()
|
||||
# Transfer this to the scaling node
|
||||
self.scalingNode.setScale(
|
||||
ohs[0] * sns[0],
|
||||
ohs[1] * sns[1],
|
||||
ohs[2] * sns[2])
|
||||
self.setScale(1)
|
||||
|
||||
def multiplyScalingFactorBy(self, factor):
|
||||
taskMgr.remove('resizeObjectHandles')
|
||||
sf = self.ohScalingFactor = self.ohScalingFactor * factor
|
||||
self.scalingNode.lerpScale(sf,sf,sf, 0.5,
|
||||
blendType = 'easeInOut',
|
||||
task = 'resizeObjectHandles')
|
||||
|
||||
def growToFit(self):
|
||||
taskMgr.remove('resizeObjectHandles')
|
||||
# Increase handles scale until they cover 80% of the min dimension
|
||||
# Originally, here is "cover 30% of the min dimension", we changed.
|
||||
pos = SEditor.widget.getPos(SEditor.camera)
|
||||
minDim = min(SEditor.dr.nearWidth, SEditor.dr.nearHeight)
|
||||
sf = 0.4 * minDim * (pos[1]/SEditor.dr.near)
|
||||
self.ohScalingFactor = sf
|
||||
self.scalingNode.lerpScale(sf,sf,sf, 0.5,
|
||||
blendType = 'easeInOut',
|
||||
task = 'resizeObjectHandles')
|
||||
|
||||
def createObjectHandleLines(self):
|
||||
# X post
|
||||
self.xPost = self.xPostGroup.attachNewNode('x-post-visible')
|
||||
lines = LineNodePath(self.xPost)
|
||||
lines.setColor(VBase4(1,0,0,1))
|
||||
lines.setThickness(5)
|
||||
lines.moveTo(0,0,0)
|
||||
lines.drawTo(1.5,0,0)
|
||||
lines.create()
|
||||
lines = LineNodePath(self.xPost)
|
||||
lines.setColor(VBase4(1,0,0,1))
|
||||
lines.setThickness(1.5)
|
||||
lines.moveTo(0,0,0)
|
||||
lines.drawTo(-1.5,0,0)
|
||||
lines.create()
|
||||
|
||||
# X ring
|
||||
self.xRing = self.xRingGroup.attachNewNode('x-ring-visible')
|
||||
lines = LineNodePath(self.xRing)
|
||||
lines.setColor(VBase4(1,0,0,1))
|
||||
lines.setThickness(3)
|
||||
lines.moveTo(0,1,0)
|
||||
for ang in range(15, 370, 15):
|
||||
lines.drawTo(0,
|
||||
math.cos(deg2Rad(ang)),
|
||||
math.sin(deg2Rad(ang)))
|
||||
lines.create()
|
||||
|
||||
# Y post
|
||||
self.yPost = self.yPostGroup.attachNewNode('y-post-visible')
|
||||
lines = LineNodePath(self.yPost)
|
||||
lines.setColor(VBase4(0,1,0,1))
|
||||
lines.setThickness(5)
|
||||
lines.moveTo(0,0,0)
|
||||
lines.drawTo(0,1.5,0)
|
||||
lines.create()
|
||||
lines = LineNodePath(self.yPost)
|
||||
lines.setColor(VBase4(0,1,0,1))
|
||||
lines.setThickness(1.5)
|
||||
lines.moveTo(0,0,0)
|
||||
lines.drawTo(0,-1.5,0)
|
||||
lines.create()
|
||||
|
||||
# Y ring
|
||||
self.yRing = self.yRingGroup.attachNewNode('y-ring-visible')
|
||||
lines = LineNodePath(self.yRing)
|
||||
lines.setColor(VBase4(0,1,0,1))
|
||||
lines.setThickness(3)
|
||||
lines.moveTo(1,0,0)
|
||||
for ang in range(15, 370, 15):
|
||||
lines.drawTo(math.cos(deg2Rad(ang)),
|
||||
0,
|
||||
math.sin(deg2Rad(ang)))
|
||||
lines.create()
|
||||
|
||||
# Z post
|
||||
self.zPost = self.zPostGroup.attachNewNode('z-post-visible')
|
||||
lines = LineNodePath(self.zPost)
|
||||
lines.setColor(VBase4(0,0,1,1))
|
||||
lines.setThickness(5)
|
||||
lines.moveTo(0,0,0)
|
||||
lines.drawTo(0,0,1.5)
|
||||
lines.create()
|
||||
lines = LineNodePath(self.zPost)
|
||||
lines.setColor(VBase4(0,0,1,1))
|
||||
lines.setThickness(1.5)
|
||||
lines.moveTo(0,0,0)
|
||||
lines.drawTo(0,0,-1.5)
|
||||
lines.create()
|
||||
|
||||
# Z ring
|
||||
self.zRing = self.zRingGroup.attachNewNode('z-ring-visible')
|
||||
lines = LineNodePath(self.zRing)
|
||||
lines.setColor(VBase4(0,0,1,1))
|
||||
lines.setThickness(3)
|
||||
lines.moveTo(1,0,0)
|
||||
for ang in range(15, 370, 15):
|
||||
lines.drawTo(math.cos(deg2Rad(ang)),
|
||||
math.sin(deg2Rad(ang)),
|
||||
0)
|
||||
lines.create()
|
||||
|
||||
def createGuideLines(self):
|
||||
self.guideLines = self.attachNewNode('guideLines')
|
||||
# X guide lines
|
||||
lines = LineNodePath(self.guideLines)
|
||||
lines.setColor(VBase4(1,0,0,1))
|
||||
lines.setThickness(0.5)
|
||||
lines.moveTo(-500,0,0)
|
||||
lines.drawTo(500,0,0)
|
||||
lines.create()
|
||||
lines.setName('x-guide')
|
||||
|
||||
# Y guide lines
|
||||
lines = LineNodePath(self.guideLines)
|
||||
lines.setColor(VBase4(0,1,0,1))
|
||||
lines.setThickness(0.5)
|
||||
lines.moveTo(0,-500,0)
|
||||
lines.drawTo(0,500,0)
|
||||
lines.create()
|
||||
lines.setName('y-guide')
|
||||
|
||||
# Z guide lines
|
||||
lines = LineNodePath(self.guideLines)
|
||||
lines.setColor(VBase4(0,0,1,1))
|
||||
lines.setThickness(0.5)
|
||||
lines.moveTo(0,0,-500)
|
||||
lines.drawTo(0,0,500)
|
||||
lines.create()
|
||||
lines.setName('z-guide')
|
||||
|
||||
def getAxisIntersectPt(self, axis):
|
||||
# Calc the xfrom from camera to widget
|
||||
mCam2Widget = SEditor.camera.getMat(SEditor.widget)
|
||||
lineDir = Vec3(mCam2Widget.xformVec(SEditor.dr.nearVec))
|
||||
lineDir.normalize()
|
||||
# And determine where the viewpoint is relative to widget
|
||||
lineOrigin = VBase3(0)
|
||||
decomposeMatrix(mCam2Widget, VBase3(0), VBase3(0), lineOrigin,
|
||||
CSDefault)
|
||||
# Now see where this hits the plane containing the 1D motion axis.
|
||||
# Pick the intersection plane most normal to the intersection ray
|
||||
# by comparing lineDir with plane normals. The plane with the
|
||||
# largest dotProduct is most "normal"
|
||||
if axis == 'x':
|
||||
if (abs(lineDir.dot(Y_AXIS)) > abs(lineDir.dot(Z_AXIS))):
|
||||
self.hitPt.assign(
|
||||
planeIntersect(lineOrigin, lineDir, ORIGIN, Y_AXIS))
|
||||
else:
|
||||
self.hitPt.assign(
|
||||
planeIntersect(lineOrigin, lineDir, ORIGIN, Z_AXIS))
|
||||
# We really only care about the nearest point on the axis
|
||||
self.hitPt.setY(0)
|
||||
self.hitPt.setZ(0)
|
||||
elif axis == 'y':
|
||||
if (abs(lineDir.dot(X_AXIS)) > abs(lineDir.dot(Z_AXIS))):
|
||||
self.hitPt.assign(
|
||||
planeIntersect(lineOrigin, lineDir, ORIGIN, X_AXIS))
|
||||
else:
|
||||
self.hitPt.assign(
|
||||
planeIntersect(lineOrigin, lineDir, ORIGIN, Z_AXIS))
|
||||
# We really only care about the nearest point on the axis
|
||||
self.hitPt.setX(0)
|
||||
self.hitPt.setZ(0)
|
||||
elif axis == 'z':
|
||||
if (abs(lineDir.dot(X_AXIS)) > abs(lineDir.dot(Y_AXIS))):
|
||||
self.hitPt.assign(
|
||||
planeIntersect(lineOrigin, lineDir, ORIGIN, X_AXIS))
|
||||
else:
|
||||
self.hitPt.assign(
|
||||
planeIntersect(lineOrigin, lineDir, ORIGIN, Y_AXIS))
|
||||
# We really only care about the nearest point on the axis
|
||||
self.hitPt.setX(0)
|
||||
self.hitPt.setY(0)
|
||||
return self.hitPt
|
||||
|
||||
def getWidgetIntersectPt(self, nodePath, plane):
|
||||
# Find out the point of interection of the ray passing though the mouse
|
||||
# with the plane containing the 2D xlation or 1D rotation widgets
|
||||
|
||||
# Calc the xfrom from camera to the nodePath
|
||||
mCam2NodePath = SEditor.camera.getMat(nodePath)
|
||||
|
||||
# And determine where the viewpoint is relative to widget
|
||||
lineOrigin = VBase3(0)
|
||||
decomposeMatrix(mCam2NodePath, VBase3(0), VBase3(0), lineOrigin,
|
||||
CSDefault)
|
||||
|
||||
# Next we find the vector from viewpoint to the widget through
|
||||
# the mouse's position on near plane.
|
||||
# This defines the intersection ray
|
||||
lineDir = Vec3(mCam2NodePath.xformVec(SEditor.dr.nearVec))
|
||||
lineDir.normalize()
|
||||
# Find the hit point
|
||||
if plane == 'x':
|
||||
self.hitPt.assign(planeIntersect(
|
||||
lineOrigin, lineDir, ORIGIN, X_AXIS))
|
||||
elif plane == 'y':
|
||||
self.hitPt.assign(planeIntersect(
|
||||
lineOrigin, lineDir, ORIGIN, Y_AXIS))
|
||||
elif plane == 'z':
|
||||
self.hitPt.assign(planeIntersect(
|
||||
lineOrigin, lineDir, ORIGIN, Z_AXIS))
|
||||
return self.hitPt
|
||||
|
||||
|
||||
|
2073
build/nirai/panda3d/contrib/src/sceneeditor/seMopathRecorder.py
Normal file
2073
build/nirai/panda3d/contrib/src/sceneeditor/seMopathRecorder.py
Normal file
File diff suppressed because it is too large
Load diff
267
build/nirai/panda3d/contrib/src/sceneeditor/seParticleEffect.py
Normal file
267
build/nirai/panda3d/contrib/src/sceneeditor/seParticleEffect.py
Normal file
|
@ -0,0 +1,267 @@
|
|||
from pandac.PandaModules import *
|
||||
import seParticles
|
||||
import seForceGroup
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
|
||||
class ParticleEffect(NodePath):
|
||||
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('ParticleEffect')
|
||||
pid = 1
|
||||
|
||||
def __init__(self, name=None, particles=None):
|
||||
"""__init__()"""
|
||||
if (name == None):
|
||||
name = 'particle-effect-%d' % ParticleEffect.pid
|
||||
ParticleEffect.pid += 1
|
||||
NodePath.__init__(self, name)
|
||||
# Record particle effect name
|
||||
self.name = name
|
||||
# Enabled flag
|
||||
self.fEnabled = 0
|
||||
# Dictionary of particles and forceGroups
|
||||
self.particlesDict = {}
|
||||
self.forceGroupDict = {}
|
||||
# The effect's particle system
|
||||
if (particles != None):
|
||||
self.addParticles(particles)
|
||||
self.renderParent = None
|
||||
|
||||
def start(self, parent=None, renderParent=None):
|
||||
assert(self.notify.debug('start() - name: %s' % self.name))
|
||||
self.renderParent = renderParent
|
||||
self.enable()
|
||||
if (parent != None):
|
||||
self.reparentTo(parent)
|
||||
|
||||
def cleanup(self):
|
||||
self.removeNode()
|
||||
self.disable()
|
||||
for f in self.forceGroupDict.values():
|
||||
f.cleanup()
|
||||
for p in self.particlesDict.values():
|
||||
p.cleanup()
|
||||
del self.renderParent
|
||||
del self.particlesDict
|
||||
del self.forceGroupDict
|
||||
|
||||
def reset(self):
|
||||
self.removeAllForces()
|
||||
self.removeAllParticles()
|
||||
self.forceGroupDict = {}
|
||||
self.particlesDict = {}
|
||||
|
||||
def enable(self):
|
||||
"""enable()"""
|
||||
if (self.renderParent != None):
|
||||
for p in self.particlesDict.values():
|
||||
p.setRenderParent(self.renderParent.node())
|
||||
for f in self.forceGroupDict.values():
|
||||
f.enable()
|
||||
for p in self.particlesDict.values():
|
||||
p.enable()
|
||||
self.fEnabled = 1
|
||||
|
||||
def disable(self):
|
||||
"""disable()"""
|
||||
self.detachNode()
|
||||
for p in self.particlesDict.values():
|
||||
p.setRenderParent(p.node)
|
||||
for f in self.forceGroupDict.values():
|
||||
f.disable()
|
||||
for p in self.particlesDict.values():
|
||||
p.disable()
|
||||
self.fEnabled = 0
|
||||
|
||||
def isEnabled(self):
|
||||
"""
|
||||
isEnabled()
|
||||
Note: this may be misleading if enable(),disable() not used
|
||||
"""
|
||||
return self.fEnabled
|
||||
|
||||
def addForceGroup(self, forceGroup):
|
||||
"""addForceGroup(forceGroup)"""
|
||||
forceGroup.nodePath.reparentTo(self)
|
||||
forceGroup.particleEffect = self
|
||||
self.forceGroupDict[forceGroup.getName()] = forceGroup
|
||||
|
||||
# Associate the force group with all particles
|
||||
for i in range(len(forceGroup)):
|
||||
self.addForce(forceGroup[i])
|
||||
|
||||
def addForce(self, force):
|
||||
"""addForce(force)"""
|
||||
for p in self.particlesDict.values():
|
||||
p.addForce(force)
|
||||
|
||||
def removeForceGroup(self, forceGroup):
|
||||
"""removeForceGroup(forceGroup)"""
|
||||
# Remove forces from all particles
|
||||
for i in range(len(forceGroup)):
|
||||
self.removeForce(forceGroup[i])
|
||||
|
||||
forceGroup.nodePath.removeNode()
|
||||
forceGroup.particleEffect = None
|
||||
del self.forceGroupDict[forceGroup.getName()]
|
||||
|
||||
def removeForce(self, force):
|
||||
"""removeForce(force)"""
|
||||
for p in self.particlesDict.values():
|
||||
p.removeForce(force)
|
||||
|
||||
def removeAllForces(self):
|
||||
for fg in self.forceGroupDict.values():
|
||||
self.removeForceGroup(fg)
|
||||
|
||||
def addParticles(self, particles):
|
||||
"""addParticles(particles)"""
|
||||
particles.nodePath.reparentTo(self)
|
||||
self.particlesDict[particles.getName()] = particles
|
||||
|
||||
# Associate all forces in all force groups with the particles
|
||||
for fg in self.forceGroupDict.values():
|
||||
for i in range(len(fg)):
|
||||
particles.addForce(fg[i])
|
||||
|
||||
def removeParticles(self, particles):
|
||||
"""removeParticles(particles)"""
|
||||
if (particles == None):
|
||||
self.notify.warning('removeParticles() - particles == None!')
|
||||
return
|
||||
particles.nodePath.detachNode()
|
||||
del self.particlesDict[particles.getName()]
|
||||
|
||||
# Remove all forces from the particles
|
||||
for fg in self.forceGroupDict.values():
|
||||
for f in fg.asList():
|
||||
particles.removeForce(f)
|
||||
|
||||
def removeAllParticles(self):
|
||||
for p in self.particlesDict.values():
|
||||
self.removeParticles(p)
|
||||
|
||||
def getParticlesList(self):
|
||||
"""getParticles()"""
|
||||
return self.particlesDict.values()
|
||||
|
||||
def getParticlesNamed(self, name):
|
||||
"""getParticlesNamed(name)"""
|
||||
return self.particlesDict.get(name, None)
|
||||
|
||||
def getParticlesDict(self):
|
||||
"""getParticlesDict()"""
|
||||
return self.particlesDict
|
||||
|
||||
def getForceGroupList(self):
|
||||
"""getForceGroup()"""
|
||||
return self.forceGroupDict.values()
|
||||
|
||||
def getForceGroupNamed(self, name):
|
||||
"""getForceGroupNamed(name)"""
|
||||
return self.forceGroupDict.get(name, None)
|
||||
|
||||
def getForceGroupDict(self):
|
||||
"""getForceGroup()"""
|
||||
return self.forceGroupDict
|
||||
|
||||
def saveConfig(self, filename):
|
||||
"""saveFileData(filename)"""
|
||||
f = open(filename.toOsSpecific(), 'wb')
|
||||
# Add a blank line
|
||||
f.write('\n')
|
||||
|
||||
# Make sure we start with a clean slate
|
||||
f.write('self.reset()\n')
|
||||
|
||||
pos = self.getPos()
|
||||
hpr = self.getHpr()
|
||||
scale = self.getScale()
|
||||
f.write('self.setPos(%0.3f, %0.3f, %0.3f)\n' %
|
||||
(pos[0], pos[1], pos[2]))
|
||||
f.write('self.setHpr(%0.3f, %0.3f, %0.3f)\n' %
|
||||
(hpr[0], hpr[1], hpr[2]))
|
||||
f.write('self.setScale(%0.3f, %0.3f, %0.3f)\n' %
|
||||
(scale[0], scale[1], scale[2]))
|
||||
|
||||
# Save all the particles to file
|
||||
num = 0
|
||||
for p in self.particlesDict.values():
|
||||
target = 'p%d' % num
|
||||
num = num + 1
|
||||
f.write(target + ' = Particles.Particles(\'%s\')\n' % p.getName())
|
||||
p.printParams(f, target)
|
||||
f.write('self.addParticles(%s)\n' % target)
|
||||
|
||||
# Save all the forces to file
|
||||
num = 0
|
||||
for fg in self.forceGroupDict.values():
|
||||
target = 'f%d' % num
|
||||
num = num + 1
|
||||
f.write(target + ' = ForceGroup.ForceGroup(\'%s\')\n' % \
|
||||
fg.getName())
|
||||
fg.printParams(f, target)
|
||||
f.write('self.addForceGroup(%s)\n' % target)
|
||||
|
||||
# Close the file
|
||||
f.close()
|
||||
|
||||
def loadConfig(self, filename):
|
||||
"""loadConfig(filename)"""
|
||||
#try:
|
||||
# if vfs:
|
||||
print vfs.readFile(filename)
|
||||
exec vfs.readFile(filename)
|
||||
print "Particle Effect Reading using VFS"
|
||||
# else:
|
||||
# execfile(filename.toOsSpecific())
|
||||
# print "Shouldnt be wrong"
|
||||
#except:
|
||||
# self.notify.error('loadConfig: failed to load particle file: '+ repr(filename))
|
||||
|
||||
|
||||
|
||||
def AppendConfig(self, f):
|
||||
f.write('\n')
|
||||
i1=" "
|
||||
i2=i1+i1
|
||||
# Make sure we start with a clean slate
|
||||
f.write(i2+'self.effect.reset()\n')
|
||||
|
||||
pos = self.getPos()
|
||||
hpr = self.getHpr()
|
||||
scale = self.getScale()
|
||||
f.write(i2+'self.effect.setPos(%0.3f, %0.3f, %0.3f)\n' %
|
||||
(pos[0], pos[1], pos[2]))
|
||||
f.write(i2+'self.effect.setHpr(%0.3f, %0.3f, %0.3f)\n' %
|
||||
(hpr[0], hpr[1], hpr[2]))
|
||||
f.write(i2+'self.effect.setScale(%0.3f, %0.3f, %0.3f)\n' %
|
||||
(scale[0], scale[1], scale[2]))
|
||||
|
||||
# Save all the particles to file
|
||||
num = 0
|
||||
for p in self.particlesDict.values():
|
||||
target = 'p%d' % num
|
||||
num = num + 1
|
||||
f.write(i2+"if(mode==0):\n")
|
||||
f.write(i2+i1+target + ' = seParticles.Particles(\'%s\')\n' % p.getName())
|
||||
f.write(i2+"else:\n")
|
||||
f.write(i2+i1+target + ' = Particles.Particles(\'%s\')\n' % p.getName())
|
||||
p.printParams(f, target)
|
||||
f.write(i2+'self.effect.addParticles(%s)\n' % target)
|
||||
|
||||
# Save all the forces to file
|
||||
num = 0
|
||||
for fg in self.forceGroupDict.values():
|
||||
target = 'f%d' % num
|
||||
num = num + 1
|
||||
f.write(i2+target + ' = ForceGroup.ForceGroup(\'%s\')\n' % \
|
||||
fg.getName())
|
||||
fg.printParams(f, target)
|
||||
f.write(i2+'self.effect.addForceGroup(%s)\n' % target)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
1976
build/nirai/panda3d/contrib/src/sceneeditor/seParticlePanel.py
Normal file
1976
build/nirai/panda3d/contrib/src/sceneeditor/seParticlePanel.py
Normal file
File diff suppressed because it is too large
Load diff
449
build/nirai/panda3d/contrib/src/sceneeditor/seParticles.py
Normal file
449
build/nirai/panda3d/contrib/src/sceneeditor/seParticles.py
Normal file
|
@ -0,0 +1,449 @@
|
|||
from pandac.PandaModules import *
|
||||
from direct.particles.ParticleManagerGlobal import *
|
||||
from direct.showbase.PhysicsManagerGlobal import *
|
||||
#Manakel 2/12/2005: replace from pandac import by from pandac.PandaModules import
|
||||
from pandac.PandaModules import ParticleSystem
|
||||
from pandac.PandaModules import BaseParticleFactory
|
||||
from pandac.PandaModules import PointParticleFactory
|
||||
from pandac.PandaModules import ZSpinParticleFactory
|
||||
#import OrientedParticleFactory
|
||||
from pandac.PandaModules import BaseParticleRenderer
|
||||
from pandac.PandaModules import PointParticleRenderer
|
||||
from pandac.PandaModules import LineParticleRenderer
|
||||
from pandac.PandaModules import GeomParticleRenderer
|
||||
from pandac.PandaModules import SparkleParticleRenderer
|
||||
from pandac.PandaModules import SpriteParticleRenderer
|
||||
from pandac.PandaModules import BaseParticleEmitter
|
||||
from pandac.PandaModules import BoxEmitter
|
||||
from pandac.PandaModules import DiscEmitter
|
||||
from pandac.PandaModules import LineEmitter
|
||||
from pandac.PandaModules import PointEmitter
|
||||
from pandac.PandaModules import RectangleEmitter
|
||||
from pandac.PandaModules import RingEmitter
|
||||
from pandac.PandaModules import SphereSurfaceEmitter
|
||||
from pandac.PandaModules import SphereVolumeEmitter
|
||||
from pandac.PandaModules import TangentRingEmitter
|
||||
import string
|
||||
import os
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
import sys
|
||||
|
||||
class Particles(ParticleSystem):
|
||||
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('Particles')
|
||||
id = 1
|
||||
|
||||
def __init__(self, name=None, poolSize=1024):
|
||||
"""__init__(name, poolSize)"""
|
||||
|
||||
if (name == None):
|
||||
self.name = 'particles-%d' % Particles.id
|
||||
Particles.id += 1
|
||||
else:
|
||||
self.name = name
|
||||
ParticleSystem.ParticleSystem.__init__(self, poolSize)
|
||||
# self.setBirthRate(0.02)
|
||||
# self.setLitterSize(10)
|
||||
# self.setLitterSpread(0)
|
||||
|
||||
# Set up a physical node
|
||||
self.node = PhysicalNode(self.name)
|
||||
self.nodePath = NodePath(self.node)
|
||||
self.setRenderParent(self.node)
|
||||
self.node.addPhysical(self)
|
||||
|
||||
self.factory = None
|
||||
self.factoryType = "undefined"
|
||||
# self.setFactory("PointParticleFactory")
|
||||
self.renderer = None
|
||||
self.rendererType = "undefined"
|
||||
# self.setRenderer("PointParticleRenderer")
|
||||
self.emitter = None
|
||||
self.emitterType = "undefined"
|
||||
# self.setEmitter("SphereVolumeEmitter")
|
||||
|
||||
# Enable particles by default
|
||||
self.fEnabled = 0
|
||||
#self.enable()
|
||||
|
||||
def cleanup(self):
|
||||
self.disable()
|
||||
self.clearLinearForces()
|
||||
self.clearAngularForces()
|
||||
self.setRenderParent(self.node)
|
||||
self.node.removePhysical(self)
|
||||
self.nodePath.removeNode()
|
||||
del self.node
|
||||
del self.nodePath
|
||||
del self.factory
|
||||
del self.renderer
|
||||
del self.emitter
|
||||
|
||||
def enable(self):
|
||||
"""enable()"""
|
||||
if (self.fEnabled == 0):
|
||||
physicsMgr.attachPhysical(self)
|
||||
particleMgr.attachParticlesystem(self)
|
||||
self.fEnabled = 1
|
||||
|
||||
def disable(self):
|
||||
"""disable()"""
|
||||
if (self.fEnabled == 1):
|
||||
physicsMgr.removePhysical(self)
|
||||
particleMgr.removeParticlesystem(self)
|
||||
self.fEnabled = 0
|
||||
|
||||
def isEnabled(self):
|
||||
return self.fEnabled
|
||||
|
||||
def getNode(self):
|
||||
return self.node
|
||||
|
||||
def setFactory(self, type):
|
||||
"""setFactory(type)"""
|
||||
if (self.factoryType == type):
|
||||
return None
|
||||
if (self.factory):
|
||||
self.factory = None
|
||||
self.factoryType = type
|
||||
if (type == "PointParticleFactory"):
|
||||
self.factory = PointParticleFactory.PointParticleFactory()
|
||||
elif (type == "ZSpinParticleFactory"):
|
||||
self.factory = ZSpinParticleFactory.ZSpinParticleFactory()
|
||||
elif (type == "OrientedParticleFactory"):
|
||||
self.factory = OrientedParticleFactory.OrientedParticleFactory()
|
||||
else:
|
||||
print "unknown factory type: %s" % type
|
||||
return None
|
||||
self.factory.setLifespanBase(0.5)
|
||||
ParticleSystem.ParticleSystem.setFactory(self, self.factory)
|
||||
|
||||
def setRenderer(self, type):
|
||||
"""setRenderer(type)"""
|
||||
if (self.rendererType == type):
|
||||
return None
|
||||
if (self.renderer):
|
||||
self.renderer = None
|
||||
self.rendererType = type
|
||||
if (type == "PointParticleRenderer"):
|
||||
self.renderer = PointParticleRenderer.PointParticleRenderer()
|
||||
self.renderer.setPointSize(1.0)
|
||||
elif (type == "LineParticleRenderer"):
|
||||
self.renderer = LineParticleRenderer.LineParticleRenderer()
|
||||
elif (type == "GeomParticleRenderer"):
|
||||
self.renderer = GeomParticleRenderer.GeomParticleRenderer()
|
||||
npath = NodePath('default-geom')
|
||||
# This was moved here because we do not want to download
|
||||
# the direct tools with toontown.
|
||||
from direct.directtools import DirectSelection
|
||||
bbox = DirectSelection.DirectBoundingBox(npath)
|
||||
self.renderer.setGeomNode(bbox.lines.node())
|
||||
elif (type == "SparkleParticleRenderer"):
|
||||
self.renderer = SparkleParticleRenderer.SparkleParticleRenderer()
|
||||
elif (type == "SpriteParticleRenderer"):
|
||||
self.renderer = SpriteParticleRenderer.SpriteParticleRenderer()
|
||||
if (self.renderer.getSourceType() ==
|
||||
SpriteParticleRenderer.SpriteParticleRenderer.STTexture):
|
||||
# Use current default texture
|
||||
# See sourceTextureName SpriteParticleRenderer-extensions.py
|
||||
self.renderer.setTextureFromFile()
|
||||
else:
|
||||
# Use current default model file and node
|
||||
# See sourceFileName and sourceNodeName in SpriteParticleRenderer-extensions.py
|
||||
self.renderer.setTextureFromNode()
|
||||
else:
|
||||
print "unknown renderer type: %s" % type
|
||||
return None
|
||||
ParticleSystem.ParticleSystem.setRenderer(self, self.renderer)
|
||||
|
||||
def setEmitter(self, type):
|
||||
"""setEmitter(type)"""
|
||||
if (self.emitterType == type):
|
||||
return None
|
||||
if (self.emitter):
|
||||
self.emitter = None
|
||||
self.emitterType = type
|
||||
if (type == "BoxEmitter"):
|
||||
self.emitter = BoxEmitter.BoxEmitter()
|
||||
elif (type == "DiscEmitter"):
|
||||
self.emitter = DiscEmitter.DiscEmitter()
|
||||
elif (type == "LineEmitter"):
|
||||
self.emitter = LineEmitter.LineEmitter()
|
||||
elif (type == "PointEmitter"):
|
||||
self.emitter = PointEmitter.PointEmitter()
|
||||
elif (type == "RectangleEmitter"):
|
||||
self.emitter = RectangleEmitter.RectangleEmitter()
|
||||
elif (type == "RingEmitter"):
|
||||
self.emitter = RingEmitter.RingEmitter()
|
||||
elif (type == "SphereSurfaceEmitter"):
|
||||
self.emitter = SphereSurfaceEmitter.SphereSurfaceEmitter()
|
||||
elif (type == "SphereVolumeEmitter"):
|
||||
self.emitter = SphereVolumeEmitter.SphereVolumeEmitter()
|
||||
self.emitter.setRadius(1.0)
|
||||
elif (type == "TangentRingEmitter"):
|
||||
self.emitter = TangentRingEmitter.TangentRingEmitter()
|
||||
else:
|
||||
print "unknown emitter type: %s" % type
|
||||
return None
|
||||
ParticleSystem.ParticleSystem.setEmitter(self, self.emitter)
|
||||
|
||||
def addForce(self, force):
|
||||
"""addForce(force)"""
|
||||
if (force.isLinear()):
|
||||
self.addLinearForce(force)
|
||||
else:
|
||||
self.addAngularForce(force)
|
||||
|
||||
def removeForce(self, force):
|
||||
"""removeForce(force)"""
|
||||
if (force == None):
|
||||
self.notify.warning('removeForce() - force == None!')
|
||||
return
|
||||
if (force.isLinear()):
|
||||
self.removeLinearForce(force)
|
||||
else:
|
||||
self.removeAngularForce(force)
|
||||
|
||||
def setRenderNodePath(self, nodePath):
|
||||
self.setRenderParent(nodePath.node())
|
||||
|
||||
## Getters ##
|
||||
def getName(self):
|
||||
"""getName()"""
|
||||
return self.name
|
||||
def getFactory(self):
|
||||
"""getFactory()"""
|
||||
return self.factory
|
||||
def getEmitter(self):
|
||||
"""getEmitter()"""
|
||||
return self.emitter
|
||||
def getRenderer(self):
|
||||
"""getRenderer()"""
|
||||
return self.renderer
|
||||
|
||||
def printParams(self, file = sys.stdout, targ = 'self'):
|
||||
"""printParams(file, targ)"""
|
||||
i1=" "
|
||||
i2=i1+i1
|
||||
file.write(i2+'# Particles parameters\n')
|
||||
file.write(i2+targ + '.setFactory(\"' + self.factoryType + '\")\n')
|
||||
file.write(i2+targ + '.setRenderer(\"' + self.rendererType + '\")\n')
|
||||
file.write(i2+targ + '.setEmitter(\"' + self.emitterType + '\")\n')
|
||||
|
||||
# System parameters
|
||||
file.write(i2+targ + ('.setPoolSize(%d)\n' %
|
||||
int(self.getPoolSize())))
|
||||
file.write(i2+targ + ('.setBirthRate(%.4f)\n' %
|
||||
self.getBirthRate()))
|
||||
file.write(i2+targ + ('.setLitterSize(%d)\n' %
|
||||
int(self.getLitterSize())))
|
||||
file.write(i2+targ + ('.setLitterSpread(%d)\n' %
|
||||
self.getLitterSpread()))
|
||||
file.write(i2+targ + ('.setSystemLifespan(%.4f)\n' %
|
||||
self.getSystemLifespan()))
|
||||
file.write(i2+targ + ('.setLocalVelocityFlag(%d)\n' %
|
||||
self.getLocalVelocityFlag()))
|
||||
file.write(i2+targ + ('.setSystemGrowsOlderFlag(%d)\n' %
|
||||
self.getSystemGrowsOlderFlag()))
|
||||
file.write(i2+'# Factory parameters\n')
|
||||
file.write(i2+targ + ('.factory.setLifespanBase(%.4f)\n' %
|
||||
self.factory.getLifespanBase()))
|
||||
file.write(i2+targ + '.factory.setLifespanSpread(%.4f)\n' % \
|
||||
self.factory.getLifespanSpread())
|
||||
file.write(i2+targ + '.factory.setMassBase(%.4f)\n' % \
|
||||
self.factory.getMassBase())
|
||||
file.write(i2+targ + '.factory.setMassSpread(%.4f)\n' % \
|
||||
self.factory.getMassSpread())
|
||||
file.write(i2+targ + '.factory.setTerminalVelocityBase(%.4f)\n' % \
|
||||
self.factory.getTerminalVelocityBase())
|
||||
file.write(i2+targ + '.factory.setTerminalVelocitySpread(%.4f)\n' % \
|
||||
self.factory.getTerminalVelocitySpread())
|
||||
if (self.factoryType == "PointParticleFactory"):
|
||||
file.write(i2+'# Point factory parameters\n')
|
||||
elif (self.factoryType == "ZSpinParticleFactory"):
|
||||
file.write(i2+'# Z Spin factory parameters\n')
|
||||
file.write(i2+targ + '.factory.setInitialAngle(%.4f)\n' % \
|
||||
self.factory.getInitialAngle())
|
||||
file.write(i2+targ + '.factory.setInitialAngleSpread(%.4f)\n' % \
|
||||
self.factory.getInitialAngleSpread())
|
||||
file.write(i2+targ + '.factory.enableAngularVelocity(%d)\n' % \
|
||||
self.factory.getAngularVelocityEnabled())
|
||||
if(self.factory.getAngularVelocityEnabled()):
|
||||
file.write(i2+targ + '.factory.setAngularVelocity(%.4f)\n' % \
|
||||
self.factory.getAngularVelocity())
|
||||
file.write(i2+targ + '.factory.setAngularVelocitySpread(%.4f)\n' % \
|
||||
self.factory.getAngularVelocitySpread())
|
||||
else:
|
||||
file.write(i2+targ + '.factory.setFinalAngle(%.4f)\n' % \
|
||||
self.factory.getFinalAngle())
|
||||
file.write(i2+targ + '.factory.setFinalAngleSpread(%.4f)\n' % \
|
||||
self.factory.getFinalAngleSpread())
|
||||
|
||||
elif (self.factoryType == "OrientedParticleFactory"):
|
||||
file.write(i2+'# Oriented factory parameters\n')
|
||||
file.write(i2+targ + '.factory.setInitialOrientation(%.4f)\n' % \
|
||||
self.factory.getInitialOrientation())
|
||||
file.write(i2+targ + '.factory.setFinalOrientation(%.4f)\n' % \
|
||||
self.factory.getFinalOrientation())
|
||||
|
||||
file.write(i2+'# Renderer parameters\n')
|
||||
alphaMode = self.renderer.getAlphaMode()
|
||||
aMode = "PRALPHANONE"
|
||||
if (alphaMode == BaseParticleRenderer.BaseParticleRenderer.PRALPHANONE):
|
||||
aMode = "PRALPHANONE"
|
||||
elif (alphaMode ==
|
||||
BaseParticleRenderer.BaseParticleRenderer.PRALPHAOUT):
|
||||
aMode = "PRALPHAOUT"
|
||||
elif (alphaMode ==
|
||||
BaseParticleRenderer.BaseParticleRenderer.PRALPHAIN):
|
||||
aMode = "PRALPHAIN"
|
||||
elif (alphaMode ==
|
||||
BaseParticleRenderer.BaseParticleRenderer.PRALPHAUSER):
|
||||
aMode = "PRALPHAUSER"
|
||||
file.write(i2+targ + '.renderer.setAlphaMode(BaseParticleRenderer.' + aMode + ')\n')
|
||||
file.write(i2+targ + '.renderer.setUserAlpha(%.2f)\n' % \
|
||||
self.renderer.getUserAlpha())
|
||||
if (self.rendererType == "PointParticleRenderer"):
|
||||
file.write(i2+'# Point parameters\n')
|
||||
file.write(i2+targ + '.renderer.setPointSize(%.2f)\n' % \
|
||||
self.renderer.getPointSize())
|
||||
sColor = self.renderer.getStartColor()
|
||||
file.write(i2+(targ + '.renderer.setStartColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
|
||||
sColor = self.renderer.getEndColor()
|
||||
file.write(i2+(targ + '.renderer.setEndColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
|
||||
blendType = self.renderer.getBlendType()
|
||||
bType = "PPONECOLOR"
|
||||
if (blendType == PointParticleRenderer.PointParticleRenderer.PPONECOLOR):
|
||||
bType = "PPONECOLOR"
|
||||
elif (blendType == PointParticleRenderer.PointParticleRenderer.PPBLENDLIFE):
|
||||
bType = "PPBLENDLIFE"
|
||||
elif (blendType == PointParticleRenderer.PointParticleRenderer.PPBLENDVEL):
|
||||
bType = "PPBLENDVEL"
|
||||
file.write(i2+targ + '.renderer.setBlendType(PointParticleRenderer.' + bType + ')\n')
|
||||
blendMethod = self.renderer.getBlendMethod()
|
||||
bMethod = "PPNOBLEND"
|
||||
if (blendMethod == BaseParticleRenderer.BaseParticleRenderer.PPNOBLEND):
|
||||
bMethod = "PPNOBLEND"
|
||||
elif (blendMethod == BaseParticleRenderer.BaseParticleRenderer.PPBLENDLINEAR):
|
||||
bMethod = "PPBLENDLINEAR"
|
||||
elif (blendMethod == BaseParticleRenderer.BaseParticleRenderer.PPBLENDCUBIC):
|
||||
bMethod = "PPBLENDCUBIC"
|
||||
file.write(i2+targ + '.renderer.setBlendMethod(BaseParticleRenderer.' + bMethod + ')\n')
|
||||
elif (self.rendererType == "LineParticleRenderer"):
|
||||
file.write(i2+'# Line parameters\n')
|
||||
sColor = self.renderer.getHeadColor()
|
||||
file.write(i2+(targ + '.renderer.setHeadColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
|
||||
sColor = self.renderer.getTailColor()
|
||||
file.write(i2+(targ + '.renderer.setTailColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
|
||||
elif (self.rendererType == "GeomParticleRenderer"):
|
||||
file.write(i2+'# Geom parameters\n')
|
||||
node = self.renderer.getGeomNode()
|
||||
file.write(i2+targ + '.renderer.setGeomNode(' + node.getName() + ')\n')
|
||||
elif (self.rendererType == "SparkleParticleRenderer"):
|
||||
file.write(i2+'# Sparkle parameters\n')
|
||||
sColor = self.renderer.getCenterColor()
|
||||
file.write(i2+(targ + '.renderer.setCenterColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
|
||||
sColor = self.renderer.getEdgeColor()
|
||||
file.write(i2+(targ + '.renderer.setEdgeColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
|
||||
file.write(i2+targ + '.renderer.setBirthRadius(%.4f)\n' % self.renderer.getBirthRadius())
|
||||
file.write(i2+targ + '.renderer.setDeathRadius(%.4f)\n' % self.renderer.getDeathRadius())
|
||||
lifeScale = self.renderer.getLifeScale()
|
||||
lScale = "SPNOSCALE"
|
||||
if (lifeScale == SparkleParticleRenderer.SparkleParticleRenderer.SPSCALE):
|
||||
lScale = "SPSCALE"
|
||||
file.write(i2+targ + '.renderer.setLifeScale(SparkleParticleRenderer.' + lScale + ')\n')
|
||||
elif (self.rendererType == "SpriteParticleRenderer"):
|
||||
file.write(i2+'# Sprite parameters\n')
|
||||
if (self.renderer.getSourceType() ==
|
||||
SpriteParticleRenderer.SpriteParticleRenderer.STTexture):
|
||||
tex = self.renderer.getTexture()
|
||||
file.write(i2+targ + '.renderer.setTexture(loader.loadTexture(\'' + tex.getFilename().getFullpath() + '\'))\n')
|
||||
else:
|
||||
modelName = self.renderer.getSourceFileName()
|
||||
nodeName = self.renderer.getSourceNodeName()
|
||||
file.write(i2+targ + '.renderer.setTextureFromNode("%s", "%s")\n' % (modelName, nodeName))
|
||||
sColor = self.renderer.getColor()
|
||||
file.write(i2+(targ + '.renderer.setColor(Vec4(%.2f, %.2f, %.2f, %.2f))\n' % (sColor[0], sColor[1], sColor[2], sColor[3])))
|
||||
file.write(i2+targ + '.renderer.setXScaleFlag(%d)\n' % self.renderer.getXScaleFlag())
|
||||
file.write(i2+targ + '.renderer.setYScaleFlag(%d)\n' % self.renderer.getYScaleFlag())
|
||||
file.write(i2+targ + '.renderer.setAnimAngleFlag(%d)\n' % self.renderer.getAnimAngleFlag())
|
||||
file.write(i2+targ + '.renderer.setInitialXScale(%.4f)\n' % self.renderer.getInitialXScale())
|
||||
file.write(i2+targ + '.renderer.setFinalXScale(%.4f)\n' % self.renderer.getFinalXScale())
|
||||
file.write(i2+targ + '.renderer.setInitialYScale(%.4f)\n' % self.renderer.getInitialYScale())
|
||||
file.write(i2+targ + '.renderer.setFinalYScale(%.4f)\n' % self.renderer.getFinalYScale())
|
||||
file.write(i2+targ + '.renderer.setNonanimatedTheta(%.4f)\n' % self.renderer.getNonanimatedTheta())
|
||||
blendMethod = self.renderer.getAlphaBlendMethod()
|
||||
bMethod = "PPNOBLEND"
|
||||
if (blendMethod == BaseParticleRenderer.BaseParticleRenderer.PPNOBLEND):
|
||||
bMethod = "PPNOBLEND"
|
||||
elif (blendMethod == BaseParticleRenderer.BaseParticleRenderer.PPBLENDLINEAR):
|
||||
bMethod = "PPBLENDLINEAR"
|
||||
elif (blendMethod == BaseParticleRenderer.BaseParticleRenderer.PPBLENDCUBIC):
|
||||
bMethod = "PPBLENDCUBIC"
|
||||
file.write(i2+targ + '.renderer.setAlphaBlendMethod(BaseParticleRenderer.' + bMethod + ')\n')
|
||||
file.write(i2+targ + '.renderer.setAlphaDisable(%d)\n' % self.renderer.getAlphaDisable())
|
||||
|
||||
file.write(i2+'# Emitter parameters\n')
|
||||
emissionType = self.emitter.getEmissionType()
|
||||
eType = "ETEXPLICIT"
|
||||
if (emissionType == BaseParticleEmitter.BaseParticleEmitter.ETEXPLICIT):
|
||||
eType = "ETEXPLICIT"
|
||||
elif (emissionType == BaseParticleEmitter.BaseParticleEmitter.ETRADIATE):
|
||||
eType = "ETRADIATE"
|
||||
elif (emissionType == BaseParticleEmitter.BaseParticleEmitter.ETCUSTOM):
|
||||
eType = "ETCUSTOM"
|
||||
file.write(i2+targ + '.emitter.setEmissionType(BaseParticleEmitter.' + eType + ')\n')
|
||||
file.write(i2+targ + '.emitter.setAmplitude(%.4f)\n' % self.emitter.getAmplitude())
|
||||
file.write(i2+targ + '.emitter.setAmplitudeSpread(%.4f)\n' % self.emitter.getAmplitudeSpread())
|
||||
oForce = self.emitter.getOffsetForce()
|
||||
file.write(i2+(targ + '.emitter.setOffsetForce(Vec3(%.4f, %.4f, %.4f))\n' % (oForce[0], oForce[1], oForce[2])))
|
||||
oForce = self.emitter.getExplicitLaunchVector()
|
||||
file.write(i2+(targ + '.emitter.setExplicitLaunchVector(Vec3(%.4f, %.4f, %.4f))\n' % (oForce[0], oForce[1], oForce[2])))
|
||||
orig = self.emitter.getRadiateOrigin()
|
||||
file.write(i2+(targ + '.emitter.setRadiateOrigin(Point3(%.4f, %.4f, %.4f))\n' % (orig[0], orig[1], orig[2])))
|
||||
if (self.emitterType == "BoxEmitter"):
|
||||
file.write(i2+'# Box parameters\n')
|
||||
bound = self.emitter.getMinBound()
|
||||
file.write(i2+(targ + '.emitter.setMinBound(Point3(%.4f, %.4f, %.4f))\n' % (bound[0], bound[1], bound[2])))
|
||||
bound = self.emitter.getMaxBound()
|
||||
file.write(i2+(targ + '.emitter.setMaxBound(Point3(%.4f, %.4f, %.4f))\n' % (bound[0], bound[1], bound[2])))
|
||||
elif (self.emitterType == "DiscEmitter"):
|
||||
file.write(i2+'# Disc parameters\n')
|
||||
file.write(i2+targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
|
||||
if (eType == "ETCUSTOM"):
|
||||
file.write(i2+targ + '.emitter.setOuterAngle(%.4f)\n' % self.emitter.getOuterAngle())
|
||||
file.write(i2+targ + '.emitter.setInnerAngle(%.4f)\n' % self.emitter.getInnerAngle())
|
||||
file.write(i2+targ + '.emitter.setOuterMagnitude(%.4f)\n' % self.emitter.getOuterMagnitude())
|
||||
file.write(i2+targ + '.emitter.setInnerMagnitude(%.4f)\n' % self.emitter.getInnerMagnitude())
|
||||
file.write(i2+targ + '.emitter.setCubicLerping(%d)\n' % self.emitter.getCubicLerping())
|
||||
|
||||
elif (self.emitterType == "LineEmitter"):
|
||||
file.write(i2+'# Line parameters\n')
|
||||
point = self.emitter.getEndpoint1()
|
||||
file.write(i2+(targ + '.emitter.setEndpoint1(Point3(%.4f, %.4f, %.4f))\n' % (point[0], point[1], point[2])))
|
||||
point = self.emitter.getEndpoint2()
|
||||
file.write(i2+(targ + '.emitter.setEndpoint2(Point3(%.4f, %.4f, %.4f))\n' % (point[0], point[1], point[2])))
|
||||
elif (self.emitterType == "PointEmitter"):
|
||||
file.write(i2+'# Point parameters\n')
|
||||
point = self.emitter.getLocation()
|
||||
file.write(i2+(targ + '.emitter.setLocation(Point3(%.4f, %.4f, %.4f))\n' % (point[0], point[1], point[2])))
|
||||
elif (self.emitterType == "RectangleEmitter"):
|
||||
file.write(i2+'# Rectangle parameters\n')
|
||||
point = self.emitter.getMinBound()
|
||||
file.write(i2+(targ + '.emitter.setMinBound(Point2(%.4f, %.4f))\n' % (point[0], point[1])))
|
||||
point = self.emitter.getMaxBound()
|
||||
file.write(i2+(targ + '.emitter.setMaxBound(Point2(%.4f, %.4f))\n' % (point[0], point[1])))
|
||||
elif (self.emitterType == "RingEmitter"):
|
||||
file.write(i2+'# Ring parameters\n')
|
||||
file.write(i2+targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
|
||||
if (eType == "ETCUSTOM"):
|
||||
file.write(i2+targ + '.emitter.setAngle(%.4f)\n' % self.emitter.getAngle())
|
||||
elif (self.emitterType == "SphereSurfaceEmitter"):
|
||||
file.write(i2+'# Sphere Surface parameters\n')
|
||||
file.write(i2+targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
|
||||
elif (self.emitterType == "SphereVolumeEmitter"):
|
||||
file.write(i2+'# Sphere Volume parameters\n')
|
||||
file.write(i2+targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
|
||||
elif (self.emitterType == "TangentRingEmitter"):
|
||||
file.write(i2+'# Tangent Ring parameters\n')
|
||||
file.write(i2+targ + '.emitter.setRadius(%.4f)\n' % self.emitter.getRadius())
|
800
build/nirai/panda3d/contrib/src/sceneeditor/sePlacer.py
Normal file
800
build/nirai/panda3d/contrib/src/sceneeditor/sePlacer.py
Normal file
|
@ -0,0 +1,800 @@
|
|||
""" DIRECT Nine DoF Manipulation Panel """
|
||||
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from direct.directtools.DirectGlobals import *
|
||||
from direct.tkwidgets.AppShell import AppShell
|
||||
from direct.tkwidgets.Dial import AngleDial
|
||||
from direct.tkwidgets.Floater import Floater
|
||||
from Tkinter import Button, Menubutton, Menu, StringVar
|
||||
from pandac.PandaModules import *
|
||||
import Tkinter, Pmw
|
||||
"""
|
||||
TODO:
|
||||
Task to monitor pose
|
||||
"""
|
||||
|
||||
class Placer(AppShell):
|
||||
# Override class variables here
|
||||
appname = 'Placer Panel'
|
||||
frameWidth = 625
|
||||
frameHeight = 215
|
||||
usecommandarea = 0
|
||||
usestatusarea = 0
|
||||
|
||||
def __init__(self, parent = None, **kw):
|
||||
INITOPT = Pmw.INITOPT
|
||||
optiondefs = (
|
||||
('title', self.appname, None),
|
||||
('nodePath', SEditor.camera, None),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
# Call superclass initialization function
|
||||
AppShell.__init__(self)
|
||||
|
||||
self.initialiseoptions(Placer)
|
||||
|
||||
# Accept the message from sceneEditor to update the information about the target nodePath
|
||||
self.accept('placerUpdate', self.updatePlacer)
|
||||
|
||||
def appInit(self):
|
||||
# Initialize state
|
||||
self.tempCS = SEditor.group.attachNewNode('placerTempCS')
|
||||
self.orbitFromCS = SEditor.group.attachNewNode(
|
||||
'placerOrbitFromCS')
|
||||
self.orbitToCS = SEditor.group.attachNewNode('placerOrbitToCS')
|
||||
self.refCS = self.tempCS
|
||||
|
||||
# Dictionary keeping track of all node paths manipulated so far
|
||||
self.nodePathDict = {}
|
||||
self.nodePathDict['camera'] = SEditor.camera
|
||||
self.nodePathDict['widget'] = SEditor.widget
|
||||
self.nodePathNames = ['camera', 'widget', 'selected']
|
||||
|
||||
self.refNodePathDict = {}
|
||||
self.refNodePathDict['parent'] = self['nodePath'].getParent()
|
||||
self.refNodePathDict['render'] = render
|
||||
self.refNodePathDict['camera'] = SEditor.camera
|
||||
self.refNodePathDict['widget'] = SEditor.widget
|
||||
self.refNodePathNames = ['parent', 'self', 'render',
|
||||
'camera', 'widget', 'selected']
|
||||
|
||||
# Initial state
|
||||
self.initPos = Vec3(0)
|
||||
self.initHpr = Vec3(0)
|
||||
self.initScale = Vec3(1)
|
||||
self.deltaHpr = Vec3(0)
|
||||
|
||||
# Offset for orbital mode
|
||||
self.posOffset = Vec3(0)
|
||||
|
||||
# Set up event hooks
|
||||
self.undoEvents = [('DIRECT_undo', self.undoHook),
|
||||
('DIRECT_pushUndo', self.pushUndoHook),
|
||||
('DIRECT_undoListEmpty', self.undoListEmptyHook),
|
||||
('DIRECT_redo', self.redoHook),
|
||||
('DIRECT_pushRedo', self.pushRedoHook),
|
||||
('DIRECT_redoListEmpty', self.redoListEmptyHook)]
|
||||
for event, method in self.undoEvents:
|
||||
self.accept(event, method)
|
||||
|
||||
# Init movement mode
|
||||
self.movementMode = 'Relative To:'
|
||||
|
||||
def createInterface(self):
|
||||
# The interior of the toplevel panel
|
||||
interior = self.interior()
|
||||
interior['relief'] = Tkinter.FLAT
|
||||
# Add placer commands to menubar
|
||||
self.menuBar.addmenu('Placer', 'Placer Panel Operations')
|
||||
self.menuBar.addmenuitem('Placer', 'command',
|
||||
'Zero Node Path',
|
||||
label = 'Zero All',
|
||||
command = self.zeroAll)
|
||||
self.menuBar.addmenuitem('Placer', 'command',
|
||||
'Reset Node Path',
|
||||
label = 'Reset All',
|
||||
command = self.resetAll)
|
||||
self.menuBar.addmenuitem('Placer', 'command',
|
||||
'Print Node Path Info',
|
||||
label = 'Print Info',
|
||||
command = self.printNodePathInfo)
|
||||
self.menuBar.addmenuitem(
|
||||
'Placer', 'command',
|
||||
'Toggle widget visability',
|
||||
label = 'Toggle Widget Vis',
|
||||
command = SEditor.toggleWidgetVis)
|
||||
self.menuBar.addmenuitem(
|
||||
'Placer', 'command',
|
||||
'Toggle widget manipulation mode',
|
||||
label = 'Toggle Widget Mode',
|
||||
command = SEditor.manipulationControl.toggleObjectHandlesMode)
|
||||
|
||||
# Get a handle to the menu frame
|
||||
menuFrame = self.menuFrame
|
||||
self.nodePathMenu = Pmw.ComboBox(
|
||||
menuFrame, labelpos = Tkinter.W, label_text = 'Node Path:',
|
||||
entry_width = 20,
|
||||
selectioncommand = self.selectNodePathNamed,
|
||||
scrolledlist_items = self.nodePathNames)
|
||||
self.nodePathMenu.selectitem('selected')
|
||||
self.nodePathMenuEntry = (
|
||||
self.nodePathMenu.component('entryfield_entry'))
|
||||
self.nodePathMenuBG = (
|
||||
self.nodePathMenuEntry.configure('background')[3])
|
||||
self.nodePathMenu.pack(side = 'left', fill = 'x', expand = 1)
|
||||
self.bind(self.nodePathMenu, 'Select node path to manipulate')
|
||||
|
||||
modeMenu = Pmw.OptionMenu(menuFrame,
|
||||
items = ('Relative To:',
|
||||
'Orbit:'),
|
||||
initialitem = 'Relative To:',
|
||||
command = self.setMovementMode,
|
||||
menubutton_width = 8)
|
||||
modeMenu.pack(side = 'left', expand = 0)
|
||||
self.bind(modeMenu, 'Select manipulation mode')
|
||||
|
||||
self.refNodePathMenu = Pmw.ComboBox(
|
||||
menuFrame, entry_width = 16,
|
||||
selectioncommand = self.selectRefNodePathNamed,
|
||||
scrolledlist_items = self.refNodePathNames)
|
||||
self.refNodePathMenu.selectitem('parent')
|
||||
self.refNodePathMenuEntry = (
|
||||
self.refNodePathMenu.component('entryfield_entry'))
|
||||
self.refNodePathMenu.pack(side = 'left', fill = 'x', expand = 1)
|
||||
self.bind(self.refNodePathMenu, 'Select relative node path')
|
||||
|
||||
self.undoButton = Button(menuFrame, text = 'Undo',
|
||||
command = SEditor.undo)
|
||||
if SEditor.undoList:
|
||||
self.undoButton['state'] = 'normal'
|
||||
else:
|
||||
self.undoButton['state'] = 'disabled'
|
||||
self.undoButton.pack(side = 'left', expand = 0)
|
||||
self.bind(self.undoButton, 'Undo last operation')
|
||||
|
||||
self.redoButton = Button(menuFrame, text = 'Redo',
|
||||
command = SEditor.redo)
|
||||
if SEditor.redoList:
|
||||
self.redoButton['state'] = 'normal'
|
||||
else:
|
||||
self.redoButton['state'] = 'disabled'
|
||||
self.redoButton.pack(side = 'left', expand = 0)
|
||||
self.bind(self.redoButton, 'Redo last operation')
|
||||
|
||||
# Create and pack the Pos Controls
|
||||
posGroup = Pmw.Group(interior,
|
||||
tag_pyclass = Menubutton,
|
||||
tag_text = 'Position',
|
||||
tag_font=('MSSansSerif', 14),
|
||||
tag_activebackground = '#909090',
|
||||
ring_relief = Tkinter.RIDGE)
|
||||
posMenubutton = posGroup.component('tag')
|
||||
self.bind(posMenubutton, 'Position menu operations')
|
||||
posMenu = Menu(posMenubutton, tearoff = 0)
|
||||
posMenu.add_command(label = 'Set to zero', command = self.zeroPos)
|
||||
posMenu.add_command(label = 'Reset initial',
|
||||
command = self.resetPos)
|
||||
posMenubutton['menu'] = posMenu
|
||||
posGroup.pack(side='left', fill = 'both', expand = 1)
|
||||
posInterior = posGroup.interior()
|
||||
|
||||
# Create the dials
|
||||
self.posX = self.createcomponent('posX', (), None,
|
||||
Floater, (posInterior,),
|
||||
text = 'X', relief = Tkinter.FLAT,
|
||||
value = 0.0,
|
||||
label_foreground = 'Red')
|
||||
self.posX['commandData'] = ['x']
|
||||
self.posX['preCallback'] = self.xformStart
|
||||
self.posX['postCallback'] = self.xformStop
|
||||
self.posX['callbackData'] = ['x']
|
||||
self.posX.pack(expand=1,fill='both')
|
||||
|
||||
self.posY = self.createcomponent('posY', (), None,
|
||||
Floater, (posInterior,),
|
||||
text = 'Y', relief = Tkinter.FLAT,
|
||||
value = 0.0,
|
||||
label_foreground = '#00A000')
|
||||
self.posY['commandData'] = ['y']
|
||||
self.posY['preCallback'] = self.xformStart
|
||||
self.posY['postCallback'] = self.xformStop
|
||||
self.posY['callbackData'] = ['y']
|
||||
self.posY.pack(expand=1,fill='both')
|
||||
|
||||
self.posZ = self.createcomponent('posZ', (), None,
|
||||
Floater, (posInterior,),
|
||||
text = 'Z', relief = Tkinter.FLAT,
|
||||
value = 0.0,
|
||||
label_foreground = 'Blue')
|
||||
self.posZ['commandData'] = ['z']
|
||||
self.posZ['preCallback'] = self.xformStart
|
||||
self.posZ['postCallback'] = self.xformStop
|
||||
self.posZ['callbackData'] = ['z']
|
||||
self.posZ.pack(expand=1,fill='both')
|
||||
|
||||
# Create and pack the Hpr Controls
|
||||
hprGroup = Pmw.Group(interior,
|
||||
tag_pyclass = Menubutton,
|
||||
tag_text = 'Orientation',
|
||||
tag_font=('MSSansSerif', 14),
|
||||
tag_activebackground = '#909090',
|
||||
ring_relief = Tkinter.RIDGE)
|
||||
hprMenubutton = hprGroup.component('tag')
|
||||
self.bind(hprMenubutton, 'Orientation menu operations')
|
||||
hprMenu = Menu(hprMenubutton, tearoff = 0)
|
||||
hprMenu.add_command(label = 'Set to zero', command = self.zeroHpr)
|
||||
hprMenu.add_command(label = 'Reset initial', command = self.resetHpr)
|
||||
hprMenubutton['menu'] = hprMenu
|
||||
hprGroup.pack(side='left',fill = 'both', expand = 1)
|
||||
hprInterior = hprGroup.interior()
|
||||
|
||||
# Create the dials
|
||||
self.hprH = self.createcomponent('hprH', (), None,
|
||||
AngleDial, (hprInterior,),
|
||||
style = 'mini',
|
||||
text = 'H', value = 0.0,
|
||||
relief = Tkinter.FLAT,
|
||||
label_foreground = 'blue')
|
||||
self.hprH['commandData'] = ['h']
|
||||
self.hprH['preCallback'] = self.xformStart
|
||||
self.hprH['postCallback'] = self.xformStop
|
||||
self.hprH['callbackData'] = ['h']
|
||||
self.hprH.pack(expand=1,fill='both')
|
||||
|
||||
self.hprP = self.createcomponent('hprP', (), None,
|
||||
AngleDial, (hprInterior,),
|
||||
style = 'mini',
|
||||
text = 'P', value = 0.0,
|
||||
relief = Tkinter.FLAT,
|
||||
label_foreground = 'red')
|
||||
self.hprP['commandData'] = ['p']
|
||||
self.hprP['preCallback'] = self.xformStart
|
||||
self.hprP['postCallback'] = self.xformStop
|
||||
self.hprP['callbackData'] = ['p']
|
||||
self.hprP.pack(expand=1,fill='both')
|
||||
|
||||
self.hprR = self.createcomponent('hprR', (), None,
|
||||
AngleDial, (hprInterior,),
|
||||
style = 'mini',
|
||||
text = 'R', value = 0.0,
|
||||
relief = Tkinter.FLAT,
|
||||
label_foreground = '#00A000')
|
||||
self.hprR['commandData'] = ['r']
|
||||
self.hprR['preCallback'] = self.xformStart
|
||||
self.hprR['postCallback'] = self.xformStop
|
||||
self.hprR['callbackData'] = ['r']
|
||||
self.hprR.pack(expand=1,fill='both')
|
||||
|
||||
# Create and pack the Scale Controls
|
||||
# The available scaling modes
|
||||
self.scalingMode = StringVar()
|
||||
self.scalingMode.set('Scale Uniform')
|
||||
# The scaling widgets
|
||||
scaleGroup = Pmw.Group(interior,
|
||||
tag_text = 'Scale Uniform',
|
||||
tag_pyclass = Menubutton,
|
||||
tag_font=('MSSansSerif', 14),
|
||||
tag_activebackground = '#909090',
|
||||
ring_relief = Tkinter.RIDGE)
|
||||
self.scaleMenubutton = scaleGroup.component('tag')
|
||||
self.bind(self.scaleMenubutton, 'Scale menu operations')
|
||||
self.scaleMenubutton['textvariable'] = self.scalingMode
|
||||
|
||||
# Scaling menu
|
||||
scaleMenu = Menu(self.scaleMenubutton, tearoff = 0)
|
||||
scaleMenu.add_command(label = 'Set to unity',
|
||||
command = self.unitScale)
|
||||
scaleMenu.add_command(label = 'Reset initial',
|
||||
command = self.resetScale)
|
||||
scaleMenu.add_radiobutton(label = 'Scale Free',
|
||||
variable = self.scalingMode)
|
||||
scaleMenu.add_radiobutton(label = 'Scale Uniform',
|
||||
variable = self.scalingMode)
|
||||
scaleMenu.add_radiobutton(label = 'Scale Proportional',
|
||||
variable = self.scalingMode)
|
||||
self.scaleMenubutton['menu'] = scaleMenu
|
||||
# Pack group widgets
|
||||
scaleGroup.pack(side='left',fill = 'both', expand = 1)
|
||||
scaleInterior = scaleGroup.interior()
|
||||
|
||||
# Create the dials
|
||||
self.scaleX = self.createcomponent('scaleX', (), None,
|
||||
Floater, (scaleInterior,),
|
||||
text = 'X Scale',
|
||||
relief = Tkinter.FLAT,
|
||||
min = 0.0001, value = 1.0,
|
||||
resetValue = 1.0,
|
||||
label_foreground = 'Red')
|
||||
self.scaleX['commandData'] = ['sx']
|
||||
self.scaleX['callbackData'] = ['sx']
|
||||
self.scaleX['preCallback'] = self.xformStart
|
||||
self.scaleX['postCallback'] = self.xformStop
|
||||
self.scaleX.pack(expand=1,fill='both')
|
||||
|
||||
self.scaleY = self.createcomponent('scaleY', (), None,
|
||||
Floater, (scaleInterior,),
|
||||
text = 'Y Scale',
|
||||
relief = Tkinter.FLAT,
|
||||
min = 0.0001, value = 1.0,
|
||||
resetValue = 1.0,
|
||||
label_foreground = '#00A000')
|
||||
self.scaleY['commandData'] = ['sy']
|
||||
self.scaleY['callbackData'] = ['sy']
|
||||
self.scaleY['preCallback'] = self.xformStart
|
||||
self.scaleY['postCallback'] = self.xformStop
|
||||
self.scaleY.pack(expand=1,fill='both')
|
||||
|
||||
self.scaleZ = self.createcomponent('scaleZ', (), None,
|
||||
Floater, (scaleInterior,),
|
||||
text = 'Z Scale',
|
||||
relief = Tkinter.FLAT,
|
||||
min = 0.0001, value = 1.0,
|
||||
resetValue = 1.0,
|
||||
label_foreground = 'Blue')
|
||||
self.scaleZ['commandData'] = ['sz']
|
||||
self.scaleZ['callbackData'] = ['sz']
|
||||
self.scaleZ['preCallback'] = self.xformStart
|
||||
self.scaleZ['postCallback'] = self.xformStop
|
||||
self.scaleZ.pack(expand=1,fill='both')
|
||||
|
||||
# Make sure appropriate labels are showing
|
||||
self.setMovementMode('Relative To:')
|
||||
# Set up placer for inital node path
|
||||
self.selectNodePathNamed('init')
|
||||
self.selectRefNodePathNamed('parent')
|
||||
# Update place to reflect initial state
|
||||
self.updatePlacer()
|
||||
# Now that you're done setting up, attach commands
|
||||
self.posX['command'] = self.xform
|
||||
self.posY['command'] = self.xform
|
||||
self.posZ['command'] = self.xform
|
||||
self.hprH['command'] = self.xform
|
||||
self.hprP['command'] = self.xform
|
||||
self.hprR['command'] = self.xform
|
||||
self.scaleX['command'] = self.xform
|
||||
self.scaleY['command'] = self.xform
|
||||
self.scaleZ['command'] = self.xform
|
||||
|
||||
|
||||
### WIDGET OPERATIONS ###
|
||||
def setMovementMode(self, movementMode):
|
||||
# Set prefix
|
||||
namePrefix = ''
|
||||
self.movementMode = movementMode
|
||||
if (movementMode == 'Relative To:'):
|
||||
namePrefix = 'Relative '
|
||||
elif (movementMode == 'Orbit:'):
|
||||
namePrefix = 'Orbit '
|
||||
# Update pos widgets
|
||||
self.posX['text'] = namePrefix + 'X'
|
||||
self.posY['text'] = namePrefix + 'Y'
|
||||
self.posZ['text'] = namePrefix + 'Z'
|
||||
# Update hpr widgets
|
||||
if (movementMode == 'Orbit:'):
|
||||
namePrefix = 'Orbit delta '
|
||||
self.hprH['text'] = namePrefix + 'H'
|
||||
self.hprP['text'] = namePrefix + 'P'
|
||||
self.hprR['text'] = namePrefix + 'R'
|
||||
# Update temp cs and initialize widgets
|
||||
self.updatePlacer()
|
||||
|
||||
def setScalingMode(self):
|
||||
if self['nodePath']:
|
||||
scale = self['nodePath'].getScale()
|
||||
if ((scale[0] != scale[1]) or
|
||||
(scale[0] != scale[2]) or
|
||||
(scale[1] != scale[2])):
|
||||
self.scalingMode.set('Scale Free')
|
||||
|
||||
def selectNodePathNamed(self, name):
|
||||
nodePath = None
|
||||
if name == 'init':
|
||||
nodePath = self['nodePath']
|
||||
# Add Combo box entry for the initial node path
|
||||
self.addNodePath(nodePath)
|
||||
elif name == 'selected':
|
||||
nodePath = SEditor.selected.last
|
||||
# Add Combo box entry for this selected object
|
||||
self.addNodePath(nodePath)
|
||||
else:
|
||||
nodePath = self.nodePathDict.get(name, None)
|
||||
if (nodePath == None):
|
||||
# See if this evaluates into a node path
|
||||
try:
|
||||
nodePath = eval(name)
|
||||
if isinstance(nodePath, NodePath):
|
||||
self.addNodePath(nodePath)
|
||||
else:
|
||||
# Good eval but not a node path, give up
|
||||
nodePath = None
|
||||
except:
|
||||
# Bogus eval
|
||||
nodePath = None
|
||||
# Clear bogus entry from listbox
|
||||
listbox = self.nodePathMenu.component('scrolledlist')
|
||||
listbox.setlist(self.nodePathNames)
|
||||
else:
|
||||
if name == 'widget':
|
||||
# Record relationship between selected nodes and widget
|
||||
SEditor.selected.getWrtAll()
|
||||
# Update active node path
|
||||
self.setActiveNodePath(nodePath)
|
||||
|
||||
def setActiveNodePath(self, nodePath):
|
||||
self['nodePath'] = nodePath
|
||||
if self['nodePath']:
|
||||
self.nodePathMenuEntry.configure(
|
||||
background = self.nodePathMenuBG)
|
||||
# Check to see if node path and ref node path are the same
|
||||
if ((self.refCS != None) and
|
||||
(self.refCS.id() == self['nodePath'].id())):
|
||||
# Yes they are, use temp CS as ref
|
||||
# This calls updatePlacer
|
||||
self.setReferenceNodePath(self.tempCS)
|
||||
# update listbox accordingly
|
||||
self.refNodePathMenu.selectitem('parent')
|
||||
else:
|
||||
# Record initial value and initialize the widgets
|
||||
self.updatePlacer()
|
||||
# Record initial position
|
||||
self.updateResetValues(self['nodePath'])
|
||||
# Set scaling mode based on node path's current scale
|
||||
self.setScalingMode()
|
||||
else:
|
||||
# Flash entry
|
||||
self.nodePathMenuEntry.configure(background = 'Pink')
|
||||
|
||||
def selectRefNodePathNamed(self, name):
|
||||
nodePath = None
|
||||
if name == 'self':
|
||||
nodePath = self.tempCS
|
||||
elif name == 'selected':
|
||||
nodePath = SEditor.selected.last
|
||||
# Add Combo box entry for this selected object
|
||||
self.addRefNodePath(nodePath)
|
||||
elif name == 'parent':
|
||||
nodePath = self['nodePath'].getParent()
|
||||
else:
|
||||
nodePath = self.refNodePathDict.get(name, None)
|
||||
if (nodePath == None):
|
||||
# See if this evaluates into a node path
|
||||
try:
|
||||
nodePath = eval(name)
|
||||
if isinstance(nodePath, NodePath):
|
||||
self.addRefNodePath(nodePath)
|
||||
else:
|
||||
# Good eval but not a node path, give up
|
||||
nodePath = None
|
||||
except:
|
||||
# Bogus eval
|
||||
nodePath = None
|
||||
# Clear bogus entry from listbox
|
||||
listbox = self.refNodePathMenu.component('scrolledlist')
|
||||
listbox.setlist(self.refNodePathNames)
|
||||
# Check to see if node path and ref node path are the same
|
||||
if (nodePath != None) and (nodePath.id() == self['nodePath'].id()):
|
||||
# Yes they are, use temp CS and update listbox accordingly
|
||||
nodePath = self.tempCS
|
||||
self.refNodePathMenu.selectitem('parent')
|
||||
# Update ref node path
|
||||
self.setReferenceNodePath(nodePath)
|
||||
|
||||
def setReferenceNodePath(self, nodePath):
|
||||
self.refCS = nodePath
|
||||
if self.refCS:
|
||||
self.refNodePathMenuEntry.configure(
|
||||
background = self.nodePathMenuBG)
|
||||
# Update placer to reflect new state
|
||||
self.updatePlacer()
|
||||
else:
|
||||
# Flash entry
|
||||
self.refNodePathMenuEntry.configure(background = 'Pink')
|
||||
|
||||
def addNodePath(self, nodePath):
|
||||
self.addNodePathToDict(nodePath, self.nodePathNames,
|
||||
self.nodePathMenu, self.nodePathDict)
|
||||
|
||||
def addRefNodePath(self, nodePath):
|
||||
self.addNodePathToDict(nodePath, self.refNodePathNames,
|
||||
self.refNodePathMenu, self.refNodePathDict)
|
||||
|
||||
def addNodePathToDict(self, nodePath, names, menu, dict):
|
||||
if not nodePath:
|
||||
return
|
||||
# Get node path's name
|
||||
name = nodePath.getName()
|
||||
if name in ['parent', 'render', 'camera']:
|
||||
dictName = name
|
||||
else:
|
||||
# Generate a unique name for the dict
|
||||
dictName = name + '-' + `nodePath.id()`
|
||||
if not dict.has_key(dictName):
|
||||
# Update combo box to include new item
|
||||
names.append(dictName)
|
||||
listbox = menu.component('scrolledlist')
|
||||
listbox.setlist(names)
|
||||
# Add new item to dictionary
|
||||
dict[dictName] = nodePath
|
||||
menu.selectitem(dictName)
|
||||
|
||||
def updatePlacer(self):
|
||||
pos = Vec3(0)
|
||||
hpr = Vec3(0)
|
||||
scale = Vec3(1)
|
||||
np = self['nodePath']
|
||||
if (np != None) and isinstance(np, NodePath):
|
||||
# Update temp CS
|
||||
self.updateAuxiliaryCoordinateSystems()
|
||||
# Update widgets
|
||||
if self.movementMode == 'Orbit:':
|
||||
pos.assign(self.posOffset)
|
||||
hpr.assign(ZERO_VEC)
|
||||
scale.assign(np.getScale())
|
||||
elif self.refCS:
|
||||
pos.assign(np.getPos(self.refCS))
|
||||
hpr.assign(np.getHpr(self.refCS))
|
||||
scale.assign(np.getScale())
|
||||
self.updatePosWidgets(pos)
|
||||
self.updateHprWidgets(hpr)
|
||||
self.updateScaleWidgets(scale)
|
||||
|
||||
def updateAuxiliaryCoordinateSystems(self):
|
||||
# Temp CS
|
||||
self.tempCS.setPosHpr(self['nodePath'], 0,0,0,0,0,0)
|
||||
# Orbit CS
|
||||
# At reference
|
||||
self.orbitFromCS.setPos(self.refCS, 0,0,0)
|
||||
# But aligned with target
|
||||
self.orbitFromCS.setHpr(self['nodePath'], 0,0,0)
|
||||
# Also update to CS
|
||||
self.orbitToCS.setPosHpr(self.orbitFromCS, 0,0,0,0,0,0)
|
||||
# Get offset from origin
|
||||
self.posOffset.assign(self['nodePath'].getPos(self.orbitFromCS))
|
||||
|
||||
### NODE PATH TRANSFORMATION OPERATIONS ###
|
||||
def xform(self, value, axis):
|
||||
if axis in ['sx', 'sy', 'sz']:
|
||||
self.xformScale(value,axis)
|
||||
elif self.movementMode == 'Relative To:':
|
||||
self.xformRelative(value, axis)
|
||||
elif self.movementMode == 'Orbit:':
|
||||
self.xformOrbit(value, axis)
|
||||
if self.nodePathMenu.get() == 'widget':
|
||||
if SEditor.manipulationControl.fSetCoa:
|
||||
# Update coa based on current widget position
|
||||
SEditor.selected.last.mCoa2Dnp.assign(
|
||||
SEditor.widget.getMat(SEditor.selected.last))
|
||||
else:
|
||||
# Move the objects with the widget
|
||||
SEditor.selected.moveWrtWidgetAll()
|
||||
|
||||
def xformStart(self, data):
|
||||
# Record undo point
|
||||
self.pushUndo()
|
||||
# If moving widget kill follow task and update wrts
|
||||
if self.nodePathMenu.get() == 'widget':
|
||||
taskMgr.remove('followSelectedNodePath')
|
||||
# Record relationship between selected nodes and widget
|
||||
SEditor.selected.getWrtAll()
|
||||
# Record initial state
|
||||
self.deltaHpr = self['nodePath'].getHpr(self.refCS)
|
||||
# Update placer to reflect new state
|
||||
self.updatePlacer()
|
||||
|
||||
def xformStop(self, data):
|
||||
# Throw event to signal manipulation done
|
||||
# Send nodepath as a list
|
||||
messenger.send('DIRECT_manipulateObjectCleanup', [[self['nodePath']]])
|
||||
# Update placer to reflect new state
|
||||
self.updatePlacer()
|
||||
# If moving widget restart follow task
|
||||
if self.nodePathMenu.get() == 'widget':
|
||||
# Restart followSelectedNodePath task
|
||||
SEditor.manipulationControl.spawnFollowSelectedNodePathTask()
|
||||
|
||||
def xformRelative(self, value, axis):
|
||||
nodePath = self['nodePath']
|
||||
if (nodePath != None) and (self.refCS != None):
|
||||
if axis == 'x':
|
||||
nodePath.setX(self.refCS, value)
|
||||
elif axis == 'y':
|
||||
nodePath.setY(self.refCS, value)
|
||||
elif axis == 'z':
|
||||
nodePath.setZ(self.refCS, value)
|
||||
else:
|
||||
if axis == 'h':
|
||||
self.deltaHpr.setX(value)
|
||||
elif axis == 'p':
|
||||
self.deltaHpr.setY(value)
|
||||
elif axis == 'r':
|
||||
self.deltaHpr.setZ(value)
|
||||
# Put node path at new hpr
|
||||
nodePath.setHpr(self.refCS, self.deltaHpr)
|
||||
|
||||
def xformOrbit(self, value, axis):
|
||||
nodePath = self['nodePath']
|
||||
if ((nodePath != None) and (self.refCS != None) and
|
||||
(self.orbitFromCS != None) and (self.orbitToCS != None)):
|
||||
if axis == 'x':
|
||||
self.posOffset.setX(value)
|
||||
elif axis == 'y':
|
||||
self.posOffset.setY(value)
|
||||
elif axis == 'z':
|
||||
self.posOffset.setZ(value)
|
||||
elif axis == 'h':
|
||||
self.orbitToCS.setH(self.orbitFromCS, value)
|
||||
elif axis == 'p':
|
||||
self.orbitToCS.setP(self.orbitFromCS, value)
|
||||
elif axis == 'r':
|
||||
self.orbitToCS.setR(self.orbitFromCS, value)
|
||||
nodePath.setPosHpr(self.orbitToCS, self.posOffset, ZERO_VEC)
|
||||
|
||||
def xformScale(self, value, axis):
|
||||
if self['nodePath']:
|
||||
mode = self.scalingMode.get()
|
||||
scale = self['nodePath'].getScale()
|
||||
if mode == 'Scale Free':
|
||||
if axis == 'sx':
|
||||
scale.setX(value)
|
||||
elif axis == 'sy':
|
||||
scale.setY(value)
|
||||
elif axis == 'sz':
|
||||
scale.setZ(value)
|
||||
elif mode == 'Scale Uniform':
|
||||
scale.set(value,value,value)
|
||||
elif mode == 'Scale Proportional':
|
||||
if axis == 'sx':
|
||||
sf = value/scale[0]
|
||||
elif axis == 'sy':
|
||||
sf = value/scale[1]
|
||||
elif axis == 'sz':
|
||||
sf = value/scale[2]
|
||||
scale = scale * sf
|
||||
self['nodePath'].setScale(scale)
|
||||
|
||||
def updatePosWidgets(self, pos):
|
||||
self.posX.set(pos[0])
|
||||
self.posY.set(pos[1])
|
||||
self.posZ.set(pos[2])
|
||||
|
||||
def updateHprWidgets(self, hpr):
|
||||
self.hprH.set(hpr[0])
|
||||
self.hprP.set(hpr[1])
|
||||
self.hprR.set(hpr[2])
|
||||
|
||||
def updateScaleWidgets(self, scale):
|
||||
self.scaleX.set(scale[0])
|
||||
self.scaleY.set(scale[1])
|
||||
self.scaleZ.set(scale[2])
|
||||
|
||||
def zeroAll(self):
|
||||
self.xformStart(None)
|
||||
self.updatePosWidgets(ZERO_VEC)
|
||||
self.updateHprWidgets(ZERO_VEC)
|
||||
self.updateScaleWidgets(UNIT_VEC)
|
||||
self.xformStop(None)
|
||||
|
||||
def zeroPos(self):
|
||||
self.xformStart(None)
|
||||
self.updatePosWidgets(ZERO_VEC)
|
||||
self.xformStop(None)
|
||||
|
||||
def zeroHpr(self):
|
||||
self.xformStart(None)
|
||||
self.updateHprWidgets(ZERO_VEC)
|
||||
self.xformStop(None)
|
||||
|
||||
def unitScale(self):
|
||||
self.xformStart(None)
|
||||
self.updateScaleWidgets(UNIT_VEC)
|
||||
self.xformStop(None)
|
||||
|
||||
def updateResetValues(self, nodePath):
|
||||
self.initPos.assign(nodePath.getPos())
|
||||
self.posX['resetValue'] = self.initPos[0]
|
||||
self.posY['resetValue'] = self.initPos[1]
|
||||
self.posZ['resetValue'] = self.initPos[2]
|
||||
self.initHpr.assign(nodePath.getHpr())
|
||||
self.hprH['resetValue'] = self.initHpr[0]
|
||||
self.hprP['resetValue'] = self.initHpr[1]
|
||||
self.hprR['resetValue'] = self.initHpr[2]
|
||||
self.initScale.assign(nodePath.getScale())
|
||||
self.scaleX['resetValue'] = self.initScale[0]
|
||||
self.scaleY['resetValue'] = self.initScale[1]
|
||||
self.scaleZ['resetValue'] = self.initScale[2]
|
||||
|
||||
def resetAll(self):
|
||||
if self['nodePath']:
|
||||
self.xformStart(None)
|
||||
self['nodePath'].setPosHprScale(
|
||||
self.initPos, self.initHpr, self.initScale)
|
||||
self.xformStop(None)
|
||||
|
||||
def resetPos(self):
|
||||
if self['nodePath']:
|
||||
self.xformStart(None)
|
||||
self['nodePath'].setPos(self.initPos)
|
||||
self.xformStop(None)
|
||||
|
||||
def resetHpr(self):
|
||||
if self['nodePath']:
|
||||
self.xformStart(None)
|
||||
self['nodePath'].setHpr(self.initHpr)
|
||||
self.xformStop(None)
|
||||
|
||||
def resetScale(self):
|
||||
if self['nodePath']:
|
||||
self.xformStart(None)
|
||||
self['nodePath'].setScale(self.initScale)
|
||||
self.xformStop(None)
|
||||
|
||||
def pushUndo(self, fResetRedo = 1):
|
||||
SEditor.pushUndo([self['nodePath']])
|
||||
|
||||
def undoHook(self, nodePathList = []):
|
||||
# Reflect new changes
|
||||
self.updatePlacer()
|
||||
|
||||
def pushUndoHook(self):
|
||||
# Make sure button is reactivated
|
||||
self.undoButton.configure(state = 'normal')
|
||||
|
||||
def undoListEmptyHook(self):
|
||||
# Make sure button is deactivated
|
||||
self.undoButton.configure(state = 'disabled')
|
||||
|
||||
def pushRedo(self):
|
||||
SEditor.pushRedo([self['nodePath']])
|
||||
|
||||
def redoHook(self, nodePathList = []):
|
||||
# Reflect new changes
|
||||
self.updatePlacer()
|
||||
|
||||
def pushRedoHook(self):
|
||||
# Make sure button is reactivated
|
||||
self.redoButton.configure(state = 'normal')
|
||||
|
||||
def redoListEmptyHook(self):
|
||||
# Make sure button is deactivated
|
||||
self.redoButton.configure(state = 'disabled')
|
||||
|
||||
def printNodePathInfo(self):
|
||||
np = self['nodePath']
|
||||
if np:
|
||||
name = np.getName()
|
||||
pos = np.getPos()
|
||||
hpr = np.getHpr()
|
||||
scale = np.getScale()
|
||||
posString = '%.2f, %.2f, %.2f' % (pos[0], pos[1], pos[2])
|
||||
hprString = '%.2f, %.2f, %.2f' % (hpr[0], hpr[1], hpr[2])
|
||||
scaleString = '%.2f, %.2f, %.2f' % (scale[0], scale[1], scale[2])
|
||||
print 'NodePath: %s' % name
|
||||
print 'Pos: %s' % posString
|
||||
print 'Hpr: %s' % hprString
|
||||
print 'Scale: %s' % scaleString
|
||||
print ('%s.setPosHprScale(%s, %s, %s)' %
|
||||
(name, posString, hprString, scaleString))
|
||||
|
||||
def onDestroy(self, event):
|
||||
# Remove hooks
|
||||
for event, method in self.undoEvents:
|
||||
self.ignore(event)
|
||||
self.tempCS.removeNode()
|
||||
self.orbitFromCS.removeNode()
|
||||
self.orbitToCS.removeNode()
|
||||
# send out a message to let sceneEditor know that placer panel has been closed.
|
||||
# Also, stop accepting the updata message from sceneEditor
|
||||
messenger.send('Placer_close')
|
||||
self.ignore('placerUpdate')
|
||||
|
||||
def place(nodePath):
|
||||
return Placer(nodePath = nodePath)
|
||||
|
||||
######################################################################
|
||||
|
||||
# Create demo in root window for testing.
|
||||
if __name__ == '__main__':
|
||||
root = Pmw.initialise()
|
||||
widget = Placer()
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
#################################################################
|
||||
# seSceneGraphExplorer.py
|
||||
# Originally from SceneGraphExplorer.py
|
||||
# Altered by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#
|
||||
# we need a customized SceneGraphExplorer.
|
||||
#
|
||||
# Do forget to check the seTree.
|
||||
#
|
||||
#################################################################
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from Tkinter import IntVar, Frame, Label
|
||||
from seTree import TreeNode, TreeItem
|
||||
import Pmw, Tkinter
|
||||
|
||||
# changing these strings requires changing sceneEditor.py SGE_ strs too!
|
||||
# This list of items will be showed on the pop out window when user right click on
|
||||
# any node on the graph. And, this is also the main reason we decide to copy from
|
||||
# the original one but not inherited from it.
|
||||
# Because except drawing part, we have changed a lot of things...
|
||||
DEFAULT_MENU_ITEMS = [
|
||||
'Update Explorer',
|
||||
'Separator',
|
||||
'Properties',
|
||||
'Separator',
|
||||
'Duplicate',
|
||||
'Remove',
|
||||
'Add Dummy',
|
||||
'Add Collision Object',
|
||||
'Metadata',
|
||||
'Separator',
|
||||
'Set as Reparent Target',
|
||||
'Reparent to Target',
|
||||
'Separator',
|
||||
'Animation Panel',
|
||||
'Blend Animation Panel',
|
||||
'MoPath Panel',
|
||||
'Align Tool',
|
||||
'Separator']
|
||||
|
||||
class seSceneGraphExplorer(Pmw.MegaWidget, DirectObject):
|
||||
"Graphical display of a scene graph"
|
||||
def __init__(self, parent = None, nodePath = render, **kw):
|
||||
# Define the megawidget options.
|
||||
optiondefs = (
|
||||
('menuItems', [], Pmw.INITOPT),
|
||||
)
|
||||
self.defineoptions(kw, optiondefs)
|
||||
|
||||
# Initialise superclass
|
||||
Pmw.MegaWidget.__init__(self, parent)
|
||||
|
||||
# Initialize some class variables
|
||||
self.nodePath = nodePath
|
||||
|
||||
# Create the components.
|
||||
|
||||
# Setup up container
|
||||
interior = self.interior()
|
||||
interior.configure(relief = Tkinter.GROOVE, borderwidth = 2)
|
||||
|
||||
# Create a label and an entry
|
||||
self._scrolledCanvas = self.createcomponent(
|
||||
'scrolledCanvas',
|
||||
(), None,
|
||||
Pmw.ScrolledCanvas, (interior,),
|
||||
hull_width = 200, hull_height = 300,
|
||||
usehullsize = 1)
|
||||
self._canvas = self._scrolledCanvas.component('canvas')
|
||||
self._canvas['scrollregion'] = ('0i', '0i', '2i', '4i')
|
||||
self._scrolledCanvas.resizescrollregion()
|
||||
self._scrolledCanvas.pack(padx = 3, pady = 3, expand=1, fill = Tkinter.BOTH)
|
||||
|
||||
self._canvas.bind('<ButtonPress-2>', self.mouse2Down)
|
||||
self._canvas.bind('<B2-Motion>', self.mouse2Motion)
|
||||
self._canvas.bind('<Configure>',
|
||||
lambda e, sc = self._scrolledCanvas:
|
||||
sc.resizescrollregion())
|
||||
self.interior().bind('<Destroy>', self.onDestroy)
|
||||
|
||||
# Create the contents
|
||||
self._treeItem = SceneGraphExplorerItem(self.nodePath)
|
||||
|
||||
self._node = TreeNode(self._canvas, None, self._treeItem,
|
||||
DEFAULT_MENU_ITEMS + self['menuItems'])
|
||||
self._node.expand()
|
||||
|
||||
self._parentFrame = Frame(interior)
|
||||
self._label = self.createcomponent(
|
||||
'parentLabel',
|
||||
(), None,
|
||||
Label, (interior,),
|
||||
text = 'Active Reparent Target: ',
|
||||
anchor = Tkinter.W, justify = Tkinter.LEFT)
|
||||
self._label.pack(fill = Tkinter.X)
|
||||
|
||||
# Add update parent label
|
||||
def updateLabel(nodePath = None, s = self):
|
||||
s._label['text'] = 'Active Reparent Target: ' + nodePath.getName()
|
||||
self.accept('DIRECT_activeParent', updateLabel)
|
||||
|
||||
# Add update hook
|
||||
self.accept('SGE_Update Explorer',
|
||||
lambda np, s = self: s.update())
|
||||
|
||||
# Check keywords and initialise options based on input values.
|
||||
self.initialiseoptions(seSceneGraphExplorer)
|
||||
|
||||
def update(self):
|
||||
""" Refresh scene graph explorer """
|
||||
self._node.update()
|
||||
|
||||
def mouse2Down(self, event):
|
||||
self._width = 1.0 * self._canvas.winfo_width()
|
||||
self._height = 1.0 * self._canvas.winfo_height()
|
||||
xview = self._canvas.xview()
|
||||
yview = self._canvas.yview()
|
||||
self._left = xview[0]
|
||||
self._top = yview[0]
|
||||
self._dxview = xview[1] - xview[0]
|
||||
self._dyview = yview[1] - yview[0]
|
||||
self._2lx = event.x
|
||||
self._2ly = event.y
|
||||
|
||||
def mouse2Motion(self,event):
|
||||
newx = self._left - ((event.x - self._2lx)/self._width) * self._dxview
|
||||
self._canvas.xview_moveto(newx)
|
||||
newy = self._top - ((event.y - self._2ly)/self._height) * self._dyview
|
||||
self._canvas.yview_moveto(newy)
|
||||
self._2lx = event.x
|
||||
self._2ly = event.y
|
||||
self._left = self._canvas.xview()[0]
|
||||
self._top = self._canvas.yview()[0]
|
||||
|
||||
def onDestroy(self, event):
|
||||
# Remove hooks
|
||||
self.ignore('DIRECT_activeParent')
|
||||
self.ignore('SGE_Update Explorer')
|
||||
|
||||
def deSelectTree(self):
|
||||
self._node.deselecttree()
|
||||
|
||||
def selectNodePath(self,nodePath, callBack=True):
|
||||
item = self._node.find(nodePath.id())
|
||||
if item!= None:
|
||||
item.select(callBack)
|
||||
else:
|
||||
print '----SGE: Error Selection'
|
||||
|
||||
class SceneGraphExplorerItem(TreeItem):
|
||||
|
||||
"""Example TreeItem subclass -- browse the file system."""
|
||||
|
||||
def __init__(self, nodePath):
|
||||
self.nodePath = nodePath
|
||||
|
||||
def GetText(self):
|
||||
type = self.nodePath.node().getType().getName()
|
||||
name = self.nodePath.getName()
|
||||
return type + " " + name
|
||||
|
||||
def GetTextForEdit(self):
|
||||
name = self.nodePath.getName()
|
||||
return name
|
||||
|
||||
def GetKey(self):
|
||||
return self.nodePath.id()
|
||||
|
||||
def IsEditable(self):
|
||||
# All nodes' names can be edited nowadays.
|
||||
return 1
|
||||
#return issubclass(self.nodePath.node().__class__, NamedNode)
|
||||
|
||||
def SetText(self, text):
|
||||
try:
|
||||
messenger.send('SGE_changeName', [self.nodePath, text])
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def GetIconName(self):
|
||||
return "sphere2" # XXX wish there was a "file" icon
|
||||
|
||||
def IsExpandable(self):
|
||||
return self.nodePath.getNumChildren() != 0
|
||||
|
||||
def GetSubList(self):
|
||||
sublist = []
|
||||
for nodePath in self.nodePath.getChildren():
|
||||
item = SceneGraphExplorerItem(nodePath)
|
||||
sublist.append(item)
|
||||
return sublist
|
||||
|
||||
def OnSelect(self, callback):
|
||||
messenger.send('SGE_Flash', [self.nodePath])
|
||||
if not callback:
|
||||
messenger.send('SGE_madeSelection', [self.nodePath, callback])
|
||||
else:
|
||||
messenger.send('SGE_madeSelection', [self.nodePath])
|
||||
|
||||
def MenuCommand(self, command):
|
||||
messenger.send('SGE_' + command, [self.nodePath])
|
||||
|
||||
|
||||
def explore(nodePath = render):
|
||||
tl = Toplevel()
|
||||
tl.title('Explore: ' + nodePath.getName())
|
||||
sge = seSceneGraphExplorer(parent = tl, nodePath = nodePath)
|
||||
sge.pack(expand = 1, fill = 'both')
|
||||
return sge
|
715
build/nirai/panda3d/contrib/src/sceneeditor/seSelection.py
Normal file
715
build/nirai/panda3d/contrib/src/sceneeditor/seSelection.py
Normal file
|
@ -0,0 +1,715 @@
|
|||
#################################################################
|
||||
# seSelection.py
|
||||
# Originally from DirectSelection.py
|
||||
# Altered by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#
|
||||
# We didn't change anything essential.
|
||||
# Just because we customized the seSession from DirectSession,
|
||||
# So we need related files can follow the change.
|
||||
# However, we don't want to change anything inside the original directool
|
||||
# to let them can work with our scene editor.
|
||||
# (If we do change original directools, it will force user has to install the latest version of OUR Panda)
|
||||
#
|
||||
#################################################################
|
||||
from pandac.PandaModules import GeomNode
|
||||
from direct.directtools.DirectGlobals import *
|
||||
from direct.directtools.DirectUtil import *
|
||||
from seGeometry import *
|
||||
from direct.showbase.DirectObject import *
|
||||
from quad import *
|
||||
COA_ORIGIN = 0
|
||||
COA_CENTER = 1
|
||||
|
||||
# MRM: To do: handle broken node paths in selected and deselected dicts
|
||||
class DirectNodePath(NodePath):
|
||||
# A node path augmented with info, bounding box, and utility methods
|
||||
def __init__(self, nodePath):
|
||||
# Initialize the superclass
|
||||
NodePath.__init__(self)
|
||||
self.assign(nodePath)
|
||||
# Create a bounding box
|
||||
self.bbox = DirectBoundingBox(self)
|
||||
center = self.bbox.getCenter()
|
||||
# Create matrix to hold the offset between the nodepath
|
||||
# and its center of action (COA)
|
||||
self.mCoa2Dnp = Mat4(Mat4.identMat())
|
||||
if SEditor.coaMode == COA_CENTER:
|
||||
self.mCoa2Dnp.setRow(3, Vec4(center[0], center[1], center[2], 1))
|
||||
|
||||
# Transform from nodePath to widget
|
||||
self.tDnp2Widget = TransformState.makeIdentity()
|
||||
|
||||
def highlight(self):
|
||||
self.bbox.show()
|
||||
|
||||
def dehighlight(self):
|
||||
self.bbox.hide()
|
||||
|
||||
def getCenter(self):
|
||||
return self.bbox.getCenter()
|
||||
|
||||
def getRadius(self):
|
||||
return self.bbox.getRadius()
|
||||
|
||||
def getMin(self):
|
||||
return self.bbox.getMin()
|
||||
|
||||
def getMax(self):
|
||||
return self.bbox.getMax()
|
||||
|
||||
class SelectedNodePaths(DirectObject):
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self.selectedDict = {}
|
||||
self.deselectedDict = {}
|
||||
__builtins__["last"] = self.last = None
|
||||
|
||||
def select(self, nodePath, fMultiSelect = 0):
|
||||
""" Select the specified node path. Multiselect as required """
|
||||
# Do nothing if nothing selected
|
||||
if not nodePath:
|
||||
print 'Nothing selected!!'
|
||||
return None
|
||||
|
||||
# Reset selected objects and highlight if multiSelect is false
|
||||
if not fMultiSelect:
|
||||
self.deselectAll()
|
||||
|
||||
# Get this pointer
|
||||
id = nodePath.id()
|
||||
# First see if its already in the selected dictionary
|
||||
dnp = self.getSelectedDict(id)
|
||||
# If so, we're done
|
||||
if not dnp:
|
||||
# See if it is in the deselected dictionary
|
||||
dnp = self.getDeselectedDict(id)
|
||||
if dnp:
|
||||
# Remove it from the deselected dictionary
|
||||
del(self.deselectedDict[id])
|
||||
# Show its bounding box
|
||||
dnp.highlight()
|
||||
else:
|
||||
# Didn't find it, create a new selectedNodePath instance
|
||||
dnp = DirectNodePath(nodePath)
|
||||
# Show its bounding box
|
||||
dnp.highlight()
|
||||
# Add it to the selected dictionary
|
||||
self.selectedDict[dnp.id()] = dnp
|
||||
# And update last
|
||||
__builtins__["last"] = self.last = dnp
|
||||
return dnp
|
||||
|
||||
def deselect(self, nodePath):
|
||||
""" Deselect the specified node path """
|
||||
# Get this pointer
|
||||
id = nodePath.id()
|
||||
# See if it is in the selected dictionary
|
||||
dnp = self.getSelectedDict(id)
|
||||
if dnp:
|
||||
# It was selected:
|
||||
# Hide its bounding box
|
||||
dnp.dehighlight()
|
||||
# Remove it from the selected dictionary
|
||||
del(self.selectedDict[id])
|
||||
# And keep track of it in the deselected dictionary
|
||||
self.deselectedDict[id] = dnp
|
||||
# Send a message
|
||||
messenger.send('DIRECT_deselectedNodePath', [dnp])
|
||||
return dnp
|
||||
|
||||
def getSelectedAsList(self):
|
||||
"""
|
||||
Return a list of all selected node paths. No verification of
|
||||
connectivity is performed on the members of the list
|
||||
"""
|
||||
return self.selectedDict.values()[:]
|
||||
|
||||
def __getitem__(self,index):
|
||||
return self.getSelectedAsList()[index]
|
||||
|
||||
def getSelectedDict(self, id):
|
||||
"""
|
||||
Search selectedDict for node path, try to repair broken node paths.
|
||||
"""
|
||||
dnp = self.selectedDict.get(id, None)
|
||||
if dnp:
|
||||
return dnp
|
||||
else:
|
||||
# Not in selected dictionary
|
||||
return None
|
||||
|
||||
def getDeselectedAsList(self):
|
||||
return self.deselectedDict.values()[:]
|
||||
|
||||
def getDeselectedDict(self, id):
|
||||
"""
|
||||
Search deselectedDict for node path, try to repair broken node paths.
|
||||
"""
|
||||
dnp = self.deselectedDict.get(id, None)
|
||||
if dnp:
|
||||
# Yes
|
||||
return dnp
|
||||
else:
|
||||
# Not in deselected dictionary
|
||||
return None
|
||||
|
||||
def forEachSelectedNodePathDo(self, func):
|
||||
"""
|
||||
Perform given func on selected node paths. No node path
|
||||
connectivity verification performed
|
||||
"""
|
||||
selectedNodePaths = self.getSelectedAsList()
|
||||
for nodePath in selectedNodePaths:
|
||||
func(nodePath)
|
||||
|
||||
def forEachDeselectedNodePathDo(self, func):
|
||||
"""
|
||||
Perform given func on deselected node paths. No node path
|
||||
connectivity verification performed
|
||||
"""
|
||||
deselectedNodePaths = self.getDeselectedAsList()
|
||||
for nodePath in deselectedNodePaths:
|
||||
func(nodePath)
|
||||
|
||||
def getWrtAll(self):
|
||||
self.forEachSelectedNodePathDo(self.getWrt)
|
||||
|
||||
def getWrt(self, nodePath):
|
||||
nodePath.tDnp2Widget = nodePath.getTransform(SEditor.widget)
|
||||
|
||||
def moveWrtWidgetAll(self):
|
||||
self.forEachSelectedNodePathDo(self.moveWrtWidget)
|
||||
|
||||
def moveWrtWidget(self, nodePath):
|
||||
nodePath.setTransform(SEditor.widget, nodePath.tDnp2Widget)
|
||||
|
||||
def deselectAll(self):
|
||||
self.forEachSelectedNodePathDo(self.deselect)
|
||||
|
||||
def highlightAll(self):
|
||||
self.forEachSelectedNodePathDo(DirectNodePath.highlight)
|
||||
|
||||
def dehighlightAll(self):
|
||||
self.forEachSelectedNodePathDo(DirectNodePath.dehighlight)
|
||||
|
||||
def removeSelected(self):
|
||||
selected = self.last
|
||||
if selected:
|
||||
selected.remove()
|
||||
__builtins__["last"] = self.last = None
|
||||
|
||||
def removeAll(self):
|
||||
# Remove all selected nodePaths from the Scene Graph
|
||||
self.forEachSelectedNodePathDo(NodePath.remove)
|
||||
|
||||
def toggleVisSelected(self):
|
||||
selected = self.last
|
||||
# Toggle visibility of selected node paths
|
||||
if selected:
|
||||
selected.toggleVis()
|
||||
|
||||
def toggleVisAll(self):
|
||||
# Toggle viz for all selected node paths
|
||||
self.forEachSelectedNodePathDo(NodePath.toggleVis)
|
||||
|
||||
def isolateSelected(self):
|
||||
selected = self.last
|
||||
if selected:
|
||||
selected.isolate()
|
||||
|
||||
def getDirectNodePath(self, nodePath):
|
||||
# Get this pointer
|
||||
id = nodePath.id()
|
||||
# First check selected dict
|
||||
dnp = self.getSelectedDict(id)
|
||||
if dnp:
|
||||
return dnp
|
||||
# Otherwise return result of deselected search
|
||||
return self.getDeselectedDict(id)
|
||||
|
||||
def getNumSelected(self):
|
||||
return len(self.selectedDict.keys())
|
||||
|
||||
|
||||
class DirectBoundingBox:
|
||||
def __init__(self, nodePath):
|
||||
# Record the node path
|
||||
self.nodePath = nodePath
|
||||
# Compute bounds, min, max, etc.
|
||||
self.computeTightBounds()
|
||||
# Generate the bounding box
|
||||
self.lines = self.createBBoxLines()
|
||||
|
||||
def computeTightBounds(self):
|
||||
# Compute bounding box using tighter calcTightBounds function
|
||||
# Need to clear out existing transform on node path
|
||||
tMat = Mat4()
|
||||
tMat.assign(self.nodePath.getMat())
|
||||
self.nodePath.clearMat()
|
||||
# Get bounds
|
||||
self.min = Point3(0)
|
||||
self.max = Point3(0)
|
||||
self.nodePath.calcTightBounds(self.min,self.max)
|
||||
# Calc center and radius
|
||||
self.center = Point3((self.min + self.max)/2.0)
|
||||
self.radius = Vec3(self.max - self.min).length()
|
||||
# Restore transform
|
||||
self.nodePath.setMat(tMat)
|
||||
del tMat
|
||||
|
||||
def computeBounds(self):
|
||||
self.bounds = self.getBounds()
|
||||
if self.bounds.isEmpty() or self.bounds.isInfinite():
|
||||
self.center = Point3(0)
|
||||
self.radius = 1.0
|
||||
else:
|
||||
self.center = self.bounds.getCenter()
|
||||
self.radius = self.bounds.getRadius()
|
||||
self.min = Point3(self.center - Point3(self.radius))
|
||||
self.max = Point3(self.center + Point3(self.radius))
|
||||
|
||||
def createBBoxLines(self):
|
||||
# Create a line segments object for the bbox
|
||||
lines = LineNodePath(hidden)
|
||||
lines.node().setName('bboxLines')
|
||||
lines.setColor( VBase4( 1., 0., 0., 1. ) )
|
||||
lines.setThickness( 0.5 )
|
||||
|
||||
minX = self.min[0]
|
||||
minY = self.min[1]
|
||||
minZ = self.min[2]
|
||||
maxX = self.max[0]
|
||||
maxY = self.max[1]
|
||||
maxZ = self.max[2]
|
||||
|
||||
# Bottom face
|
||||
lines.moveTo( minX, minY, minZ )
|
||||
lines.drawTo( maxX, minY, minZ )
|
||||
lines.drawTo( maxX, maxY, minZ )
|
||||
lines.drawTo( minX, maxY, minZ )
|
||||
lines.drawTo( minX, minY, minZ )
|
||||
|
||||
# Front Edge/Top face
|
||||
lines.drawTo( minX, minY, maxZ )
|
||||
lines.drawTo( maxX, minY, maxZ )
|
||||
lines.drawTo( maxX, maxY, maxZ )
|
||||
lines.drawTo( minX, maxY, maxZ )
|
||||
lines.drawTo( minX, minY, maxZ )
|
||||
|
||||
# Three remaining edges
|
||||
lines.moveTo( maxX, minY, minZ )
|
||||
lines.drawTo( maxX, minY, maxZ )
|
||||
lines.moveTo( maxX, maxY, minZ )
|
||||
lines.drawTo( maxX, maxY, maxZ )
|
||||
lines.moveTo( minX, maxY, minZ )
|
||||
lines.drawTo( minX, maxY, maxZ )
|
||||
|
||||
# Create and return bbox lines
|
||||
lines.create()
|
||||
|
||||
# Make sure bbox is never lit or drawn in wireframe
|
||||
useDirectRenderStyle(lines)
|
||||
|
||||
return lines
|
||||
|
||||
def updateBBoxLines(self):
|
||||
ls = self.lines.lineSegs
|
||||
|
||||
minX = self.min[0]
|
||||
minY = self.min[1]
|
||||
minZ = self.min[2]
|
||||
maxX = self.max[0]
|
||||
maxY = self.max[1]
|
||||
maxZ = self.max[2]
|
||||
|
||||
# Bottom face
|
||||
ls.setVertex( 0, minX, minY, minZ )
|
||||
ls.setVertex( 1, maxX, minY, minZ )
|
||||
ls.setVertex( 2, maxX, maxY, minZ )
|
||||
ls.setVertex( 3, minX, maxY, minZ )
|
||||
ls.setVertex( 4, minX, minY, minZ )
|
||||
|
||||
# Front Edge/Top face
|
||||
ls.setVertex( 5, minX, minY, maxZ )
|
||||
ls.setVertex( 6, maxX, minY, maxZ )
|
||||
ls.setVertex( 7, maxX, maxY, maxZ )
|
||||
ls.setVertex( 8, minX, maxY, maxZ )
|
||||
ls.setVertex( 9, minX, minY, maxZ )
|
||||
|
||||
# Three remaining edges
|
||||
ls.setVertex( 10, maxX, minY, minZ )
|
||||
ls.setVertex( 11, maxX, minY, maxZ )
|
||||
ls.setVertex( 12, maxX, maxY, minZ )
|
||||
ls.setVertex( 13, maxX, maxY, maxZ )
|
||||
ls.setVertex( 14, minX, maxY, minZ )
|
||||
ls.setVertex( 15, minX, maxY, maxZ )
|
||||
|
||||
def getBounds(self):
|
||||
# Get a node path's bounds
|
||||
nodeBounds = BoundingSphere()
|
||||
nodeBounds.extendBy(self.nodePath.node().getInternalBound())
|
||||
for child in self.nodePath.getChildren():
|
||||
nodeBounds.extendBy(child.getBounds())
|
||||
return nodeBounds.makeCopy()
|
||||
|
||||
def show(self):
|
||||
self.lines.reparentTo(self.nodePath)
|
||||
|
||||
def hide(self):
|
||||
self.lines.reparentTo(hidden)
|
||||
|
||||
def getCenter(self):
|
||||
return self.center
|
||||
|
||||
def getRadius(self):
|
||||
return self.radius
|
||||
|
||||
def getMin(self):
|
||||
return self.min
|
||||
|
||||
def getMax(self):
|
||||
return self.max
|
||||
|
||||
def vecAsString(self, vec):
|
||||
return '%.2f %.2f %.2f' % (vec[0], vec[1], vec[2])
|
||||
|
||||
def __repr__(self):
|
||||
return (`self.__class__` +
|
||||
'\nNodePath:\t%s\n' % self.nodePath.getName() +
|
||||
'Min:\t\t%s\n' % self.vecAsString(self.min) +
|
||||
'Max:\t\t%s\n' % self.vecAsString(self.max) +
|
||||
'Center:\t\t%s\n' % self.vecAsString(self.center) +
|
||||
'Radius:\t\t%.2f' % self.radius
|
||||
)
|
||||
|
||||
|
||||
class SelectionQueue(CollisionHandlerQueue):
|
||||
def __init__(self, parentNP = render):
|
||||
# Initialize the superclass
|
||||
CollisionHandlerQueue.__init__(self)
|
||||
# Current index and entry in collision queue
|
||||
self.index = -1
|
||||
self.entry = None
|
||||
self.skipFlags = SKIP_NONE
|
||||
# Create a collision node path attached to the given NP
|
||||
self.collisionNodePath = NodePath(CollisionNode("collisionNP"))
|
||||
self.setParentNP(parentNP)
|
||||
# Don't pay the penalty of drawing this collision ray
|
||||
self.collisionNodePath.hide()
|
||||
self.collisionNode = self.collisionNodePath.node()
|
||||
# Intersect with geometry to begin with
|
||||
self.collideWithGeom()
|
||||
# And a traverser to do the actual collision tests
|
||||
self.ct = CollisionTraverser()
|
||||
# Let the traverser know about the collision node and the queue
|
||||
#Manakel 2/12/2005: replace CollisionNode by its nodepath
|
||||
self.ct.addCollider(self.collisionNodePath, self)
|
||||
# List of objects that can't be selected
|
||||
self.unpickable = UNPICKABLE
|
||||
# Derived class must add Collider to complete initialization
|
||||
|
||||
def setParentNP(self, parentNP):
|
||||
# Update collisionNodePath's parent
|
||||
self.collisionNodePath.reparentTo(parentNP)
|
||||
|
||||
def addCollider(self, collider):
|
||||
# Inherited class must call this function to specify collider object
|
||||
# Record collision object
|
||||
self.collider = collider
|
||||
# Add the collider to the collision Node
|
||||
self.collisionNode.addSolid( self.collider )
|
||||
|
||||
def collideWithBitMask(self, bitMask):
|
||||
# The into collide mask is the bit pattern colliders look at
|
||||
# when deciding whether or not to test for a collision "into"
|
||||
# this collision solid. Set to all Off so this collision solid
|
||||
# will not be considered in any collision tests
|
||||
self.collisionNode.setIntoCollideMask(BitMask32().allOff())
|
||||
# The from collide mask is the bit pattern *this* collision solid
|
||||
# compares against the into collide mask of candidate collision solids
|
||||
# Turn this mask all off since we're not testing for collisions against
|
||||
# collision solids
|
||||
self.collisionNode.setFromCollideMask(bitMask)
|
||||
|
||||
def collideWithGeom(self):
|
||||
# The into collide mask is the bit pattern colliders look at
|
||||
# when deciding whether or not to test for a collision "into"
|
||||
# this collision solid. Set to all Off so this collision solid
|
||||
# will not be considered in any collision tests
|
||||
self.collisionNode.setIntoCollideMask(BitMask32().allOff())
|
||||
# The from collide mask is the bit pattern *this* collision solid
|
||||
# compares against the into collide mask of candidate collision solids
|
||||
# Turn this mask all off since we're not testing for collisions against
|
||||
# collision solids, but we do want to test against geometry
|
||||
self.collisionNode.setFromCollideMask(GeomNode.getDefaultCollideMask())
|
||||
|
||||
def collideWithWidget(self):
|
||||
# This collision node should not be tested against by any other
|
||||
# collision solids
|
||||
self.collisionNode.setIntoCollideMask(BitMask32().allOff())
|
||||
# This collision node will test for collisions with any collision
|
||||
# solids with a bit mask set to 0x80000000
|
||||
mask = BitMask32()
|
||||
mask.setBit(31)
|
||||
self.collisionNode.setFromCollideMask(mask)
|
||||
|
||||
def addUnpickable(self, item):
|
||||
if item not in self.unpickable:
|
||||
self.unpickable.append(item)
|
||||
|
||||
def removeUnpickable(self, item):
|
||||
if item in self.unpickable:
|
||||
self.unpickable.remove(item)
|
||||
|
||||
def setCurrentIndex(self, index):
|
||||
if (index < 0) or (index >= self.getNumEntries()):
|
||||
self.index = -1
|
||||
else:
|
||||
self.index = index
|
||||
|
||||
def setCurrentEntry(self, entry):
|
||||
self.entry = entry
|
||||
|
||||
def getCurrentEntry(self):
|
||||
return self.entry
|
||||
|
||||
def isEntryBackfacing(self, entry):
|
||||
# If dot product of collision point surface normal and
|
||||
# ray from camera to collision point is positive, we are
|
||||
# looking at the backface of the polygon
|
||||
if not entry.hasSurfaceNormal():
|
||||
# Well, no way to tell. Assume we're not backfacing.
|
||||
return 0
|
||||
|
||||
fromNodePath = entry.getFromNodePath()
|
||||
v = Vec3(entry.getSurfacePoint(fromNodePath))
|
||||
n = entry.getSurfaceNormal(fromNodePath)
|
||||
# Convert to camera space for backfacing test
|
||||
if self.collisionNodePath.getParent() != base.cam:
|
||||
# Problem: assumes base.cam is the camera in question
|
||||
p2cam = self.collisionNodePath.getParent().getMat(base.cam)
|
||||
v = Vec3(p2cam.xformPoint(v))
|
||||
n = p2cam.xformVec(n)
|
||||
# Normalize and check angle between to vectors
|
||||
v.normalize()
|
||||
return v.dot(n) >= 0
|
||||
|
||||
def findNextCollisionEntry(self, skipFlags = SKIP_NONE):
|
||||
return self.findCollisionEntry(skipFlags, self.index + 1)
|
||||
|
||||
def findCollisionEntry(self, skipFlags = SKIP_NONE, startIndex = 0 ):
|
||||
# Init self.index and self.entry
|
||||
self.setCurrentIndex(-1)
|
||||
self.setCurrentEntry(None)
|
||||
# Pick out the closest object that isn't a widget
|
||||
for i in range(startIndex,self.getNumEntries()):
|
||||
entry = self.getEntry(i)
|
||||
nodePath = entry.getIntoNodePath()
|
||||
if (skipFlags & SKIP_HIDDEN) and nodePath.isHidden():
|
||||
# Skip if hidden node
|
||||
pass
|
||||
elif (skipFlags & SKIP_BACKFACE) and self.isEntryBackfacing(entry):
|
||||
# Skip, if backfacing poly
|
||||
pass
|
||||
elif ((skipFlags & SKIP_CAMERA) and
|
||||
(camera in nodePath.getAncestors())):
|
||||
# Skip if parented to a camera.
|
||||
pass
|
||||
# Can pick unpickable, use the first visible node
|
||||
elif ((skipFlags & SKIP_UNPICKABLE) and
|
||||
(nodePath.getName() in self.unpickable)):
|
||||
# Skip if in unpickable list
|
||||
pass
|
||||
else:
|
||||
self.setCurrentIndex(i)
|
||||
self.setCurrentEntry(entry)
|
||||
break
|
||||
return self.getCurrentEntry()
|
||||
|
||||
class SelectionRay(SelectionQueue):
|
||||
def __init__(self, parentNP = render):
|
||||
# Initialize the superclass
|
||||
SelectionQueue.__init__(self, parentNP)
|
||||
self.addCollider(CollisionRay())
|
||||
|
||||
def pick(self, targetNodePath, xy = None):
|
||||
# Determine ray direction based upon the mouse coordinates
|
||||
if xy:
|
||||
mx = xy[0]
|
||||
my = xy[1]
|
||||
elif direct:
|
||||
mx = SEditor.dr.mouseX
|
||||
my = SEditor.dr.mouseY
|
||||
else:
|
||||
if not base.mouseWatcherNode.hasMouse():
|
||||
# No mouse in window.
|
||||
self.clearEntries()
|
||||
return
|
||||
mx = base.mouseWatcherNode.getMouseX()
|
||||
my = base.mouseWatcherNode.getMouseY()
|
||||
#base.mouseWatcherNode.setDisplayRegion(base.win.getDisplayRegion(0))
|
||||
#mx = base.mouseWatcherNode.getMouseX()+1
|
||||
#my = base.mouseWatcherNode.getMouseY()+1
|
||||
#print base.camNode.getName()
|
||||
#print "Arrived X" + str(mx) + " Arrived Y " + str(my)
|
||||
self.collider.setFromLens( base.camNode, mx, my )
|
||||
|
||||
self.ct.traverse( targetNodePath )
|
||||
self.sortEntries()
|
||||
|
||||
|
||||
def pickBitMask(self, bitMask = BitMask32.allOff(),
|
||||
targetNodePath = render,
|
||||
skipFlags = SKIP_ALL ):
|
||||
self.collideWithBitMask(bitMask)
|
||||
self.pick(targetNodePath)
|
||||
# Determine collision entry
|
||||
return self.findCollisionEntry(skipFlags)
|
||||
|
||||
def pickGeom(self, targetNodePath = render, skipFlags = SKIP_ALL,
|
||||
xy = None):
|
||||
self.collideWithGeom()
|
||||
self.pick(targetNodePath, xy = xy)
|
||||
# Determine collision entry
|
||||
return self.findCollisionEntry(skipFlags)
|
||||
|
||||
def pickWidget(self, targetNodePath = render, skipFlags = SKIP_NONE ):
|
||||
self.collideWithWidget()
|
||||
self.pick(targetNodePath)
|
||||
# Determine collision entry
|
||||
return self.findCollisionEntry(skipFlags)
|
||||
|
||||
def pick3D(self, targetNodePath, origin, dir):
|
||||
# Determine ray direction based upon the mouse coordinates
|
||||
self.collider.setOrigin( origin )
|
||||
self.collider.setDirection( dir )
|
||||
self.ct.traverse( targetNodePath )
|
||||
self.sortEntries()
|
||||
|
||||
def pickGeom3D(self, targetNodePath = render,
|
||||
origin = Point3(0), dir = Vec3(0,0,-1),
|
||||
skipFlags = SKIP_HIDDEN | SKIP_CAMERA ):
|
||||
self.collideWithGeom()
|
||||
self.pick3D(targetNodePath, origin, dir)
|
||||
# Determine collision entry
|
||||
return self.findCollisionEntry(skipFlags)
|
||||
|
||||
def pickBitMask3D(self, bitMask = BitMask32.allOff(),
|
||||
targetNodePath = render,
|
||||
origin = Point3(0), dir = Vec3(0,0,-1),
|
||||
skipFlags = SKIP_ALL ):
|
||||
self.collideWithBitMask(bitMask)
|
||||
self.pick3D(targetNodePath, origin, dir)
|
||||
# Determine collision entry
|
||||
return self.findCollisionEntry(skipFlags)
|
||||
|
||||
|
||||
class SelectionSegment(SelectionQueue):
|
||||
# Like a selection ray but with two endpoints instead of an endpoint
|
||||
# and a direction
|
||||
def __init__(self, parentNP = render, numSegments = 1):
|
||||
# Initialize the superclass
|
||||
SelectionQueue.__init__(self, parentNP)
|
||||
self.colliders = []
|
||||
self.numColliders = 0
|
||||
for i in range(numSegments):
|
||||
self.addCollider(CollisionSegment())
|
||||
|
||||
def addCollider(self, collider):
|
||||
# Record new collision object
|
||||
self.colliders.append(collider)
|
||||
# Add the collider to the collision Node
|
||||
self.collisionNode.addSolid( collider )
|
||||
self.numColliders += 1
|
||||
|
||||
def pickGeom(self, targetNodePath = render, endPointList = [],
|
||||
skipFlags = SKIP_HIDDEN | SKIP_CAMERA ):
|
||||
self.collideWithGeom()
|
||||
for i in range(min(len(endPointList), self.numColliders)):
|
||||
pointA, pointB = endPointList[i]
|
||||
collider = self.colliders[i]
|
||||
collider.setPointA( pointA )
|
||||
collider.setPointB( pointB )
|
||||
self.ct.traverse( targetNodePath )
|
||||
# Determine collision entry
|
||||
return self.findCollisionEntry(skipFlags)
|
||||
|
||||
def pickBitMask(self, bitMask = BitMask32.allOff(),
|
||||
targetNodePath = render, endPointList = [],
|
||||
skipFlags = SKIP_HIDDEN | SKIP_CAMERA ):
|
||||
self.collideWithBitMask(bitMask)
|
||||
for i in range(min(len(endPointList), self.numColliders)):
|
||||
pointA, pointB = endPointList[i]
|
||||
collider = self.colliders[i]
|
||||
collider.setPointA( pointA )
|
||||
collider.setPointB( pointB )
|
||||
self.ct.traverse( targetNodePath )
|
||||
# Determine collision entry
|
||||
return self.findCollisionEntry(skipFlags)
|
||||
|
||||
|
||||
class SelectionSphere(SelectionQueue):
|
||||
# Wrapper around collision sphere
|
||||
def __init__(self, parentNP = render, numSpheres = 1):
|
||||
# Initialize the superclass
|
||||
SelectionQueue.__init__(self, parentNP)
|
||||
self.colliders = []
|
||||
self.numColliders = 0
|
||||
for i in range(numSpheres):
|
||||
self.addCollider(CollisionSphere(Point3(0), 1))
|
||||
|
||||
def addCollider(self, collider):
|
||||
# Record new collision object
|
||||
self.colliders.append(collider)
|
||||
# Add the collider to the collision Node
|
||||
self.collisionNode.addSolid( collider )
|
||||
self.numColliders += 1
|
||||
|
||||
def setCenter(self, i, center):
|
||||
c = self.colliders[i]
|
||||
c.setCenter(center)
|
||||
|
||||
def setRadius(self, i, radius):
|
||||
c = self.colliders[i]
|
||||
c.setRadius(radius)
|
||||
|
||||
def setCenterRadius(self, i, center, radius):
|
||||
c = self.colliders[i]
|
||||
c.setCenter(center)
|
||||
c.setRadius(radius)
|
||||
|
||||
def isEntryBackfacing(self, entry):
|
||||
# If dot product of collision point surface normal and
|
||||
# ray from sphere origin to collision point is positive,
|
||||
# center is on the backside of the polygon
|
||||
fromNodePath = entry.getFromNodePath()
|
||||
v = Vec3(entry.getSurfacePoint(fromNodePath) -
|
||||
entry.getFrom().getCenter())
|
||||
n = entry.getSurfaceNormal(fromNodePath)
|
||||
# If points almost on top of each other, reject face
|
||||
# (treat as backfacing)
|
||||
if v.length() < 0.05:
|
||||
return 1
|
||||
# Normalize and check angle between to vectors
|
||||
v.normalize()
|
||||
return v.dot(n) >= 0
|
||||
|
||||
|
||||
def pick(self, targetNodePath, skipFlags):
|
||||
self.ct.traverse( targetNodePath )
|
||||
self.sortEntries()
|
||||
return self.findCollisionEntry(skipFlags)
|
||||
|
||||
def pickGeom(self, targetNodePath = render,
|
||||
skipFlags = SKIP_HIDDEN | SKIP_CAMERA ):
|
||||
self.collideWithGeom()
|
||||
return self.pick(targetNodePath, skipFlags)
|
||||
|
||||
def pickBitMask(self, bitMask = BitMask32.allOff(),
|
||||
targetNodePath = render,
|
||||
skipFlags = SKIP_HIDDEN | SKIP_CAMERA ):
|
||||
self.collideWithBitMask(bitMask)
|
||||
return self.pick(targetNodePath, skipFlags)
|
||||
|
991
build/nirai/panda3d/contrib/src/sceneeditor/seSession.py
Normal file
991
build/nirai/panda3d/contrib/src/sceneeditor/seSession.py
Normal file
|
@ -0,0 +1,991 @@
|
|||
#################################################################
|
||||
# seSession.py
|
||||
# Originally from DirectSession.py
|
||||
# Altered by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#
|
||||
# We took out a lot of stuff we don't need in the sceneeditor.
|
||||
# This is also the main reason we didn't just inherite the original directSession.
|
||||
# Also, the way of selecting, renaming and some hot-key controls are changed.
|
||||
#
|
||||
#################################################################
|
||||
from direct.showbase.DirectObject import *
|
||||
from direct.directtools.DirectGlobals import *
|
||||
from direct.directtools.DirectUtil import*
|
||||
from direct.interval.IntervalGlobal import *
|
||||
from seCameraControl import *
|
||||
from seManipulation import *
|
||||
from seSelection import *
|
||||
from seGrid import *
|
||||
from seGeometry import *
|
||||
from direct.tkpanels import Placer
|
||||
from direct.tkwidgets import Slider
|
||||
from direct.gui import OnscreenText
|
||||
import types
|
||||
import string
|
||||
from direct.showbase import Loader
|
||||
|
||||
class SeSession(DirectObject): ### Customized DirectSession
|
||||
|
||||
def __init__(self):
|
||||
# Establish a global pointer to the direct object early on
|
||||
# so dependant classes can access it in their code
|
||||
__builtins__["SEditor"] = self
|
||||
# These come early since they are used later on
|
||||
self.group = render.attachNewNode('SEditor')
|
||||
self.font = TextNode.getDefaultFont()
|
||||
self.fEnabled = 0
|
||||
self.drList = DisplayRegionList()
|
||||
self.iRayList = map(lambda x: x.iRay, self.drList)
|
||||
self.dr = self.drList[0]
|
||||
self.camera = base.camera
|
||||
self.trueCamera = self.camera
|
||||
self.iRay = self.dr.iRay
|
||||
self.coaMode = COA_ORIGIN
|
||||
|
||||
self.enableAutoCamera = True
|
||||
|
||||
self.cameraControl = DirectCameraControl()
|
||||
self.manipulationControl = DirectManipulationControl()
|
||||
self.useObjectHandles()
|
||||
self.grid = DirectGrid()
|
||||
self.grid.disable()
|
||||
|
||||
# Initialize the collection of selected nodePaths
|
||||
self.selected = SelectedNodePaths()
|
||||
# Ancestry of currently selected object
|
||||
self.ancestry = []
|
||||
self.ancestryIndex = 0
|
||||
self.activeParent = None
|
||||
|
||||
self.selectedNPReadout = OnscreenText.OnscreenText(
|
||||
pos = (-1.0, -0.9), bg=Vec4(1,1,1,1),
|
||||
scale = 0.05, align = TextNode.ALeft,
|
||||
mayChange = 1, font = self.font)
|
||||
# Make sure readout is never lit or drawn in wireframe
|
||||
useDirectRenderStyle(self.selectedNPReadout)
|
||||
self.selectedNPReadout.reparentTo(hidden)
|
||||
|
||||
self.activeParentReadout = OnscreenText.OnscreenText(
|
||||
pos = (-1.0, -0.975), bg=Vec4(1,1,1,1),
|
||||
scale = 0.05, align = TextNode.ALeft,
|
||||
mayChange = 1, font = self.font)
|
||||
# Make sure readout is never lit or drawn in wireframe
|
||||
useDirectRenderStyle(self.activeParentReadout)
|
||||
self.activeParentReadout.reparentTo(hidden)
|
||||
|
||||
self.directMessageReadout = OnscreenText.OnscreenText(
|
||||
pos = (-1.0, 0.9), bg=Vec4(1,1,1,1),
|
||||
scale = 0.05, align = TextNode.ALeft,
|
||||
mayChange = 1, font = self.font)
|
||||
# Make sure readout is never lit or drawn in wireframe
|
||||
useDirectRenderStyle(self.directMessageReadout)
|
||||
self.directMessageReadout.reparentTo(hidden)
|
||||
|
||||
self.fControl = 0
|
||||
self.fAlt = 0
|
||||
self.fShift = 0
|
||||
|
||||
self.pos = VBase3()
|
||||
self.hpr = VBase3()
|
||||
self.scale = VBase3()
|
||||
|
||||
self.hitPt = Point3(0.0)
|
||||
|
||||
# Lists for managing undo/redo operations
|
||||
self.undoList = []
|
||||
self.redoList = []
|
||||
|
||||
# One run through the context task to init everything
|
||||
self.drList.updateContext()
|
||||
for dr in self.drList:
|
||||
dr.camUpdate()
|
||||
|
||||
|
||||
|
||||
self.modifierEvents = ['control', 'control-up',
|
||||
'shift', 'shift-up',
|
||||
'alt', 'alt-up',
|
||||
]
|
||||
self.keyEvents = ['escape', 'delete', 'page_up', 'page_down',
|
||||
'[', '{', ']', '}',
|
||||
'shift-a', 'b', 'control-f',
|
||||
'l', 'shift-l', 'o', 'p', 'r',
|
||||
'shift-r', 's', 't', 'v', 'w']
|
||||
self.mouseEvents = ['mouse1', 'mouse1-up',
|
||||
'shift-mouse1', 'shift-mouse1-up',
|
||||
'control-mouse1', 'control-mouse1-up',
|
||||
'alt-mouse1', 'alt-mouse1-up',
|
||||
'mouse2', 'mouse2-up',
|
||||
'shift-mouse2', 'shift-mouse2-up',
|
||||
'control-mouse2', 'control-mouse2-up',
|
||||
'alt-mouse2', 'alt-mouse2-up',
|
||||
'mouse3', 'mouse3-up',
|
||||
'shift-mouse3', 'shift-mouse3-up',
|
||||
'control-mouse3', 'control-mouse3-up',
|
||||
'alt-mouse3', 'alt-mouse3-up',
|
||||
]
|
||||
|
||||
def enable(self):
|
||||
if self.fEnabled:
|
||||
return
|
||||
# Make sure old tasks are shut down
|
||||
self.disable()
|
||||
# Start all display region context tasks
|
||||
self.drList.spawnContextTask()
|
||||
# Turn on mouse Flying
|
||||
self.cameraControl.enableMouseFly()
|
||||
# Turn on object manipulation
|
||||
self.manipulationControl.enableManipulation()
|
||||
# Make sure list of selected items is reset
|
||||
self.selected.reset()
|
||||
# Accept appropriate hooks
|
||||
self.enableKeyEvents()
|
||||
self.enableModifierEvents()
|
||||
self.enableMouseEvents()
|
||||
# Set flag
|
||||
self.fEnabled = 1
|
||||
|
||||
if self.enableAutoCamera:
|
||||
self.accept('DH_LoadingComplete', self.autoCameraMove)
|
||||
|
||||
def disable(self):
|
||||
# Shut down all display region context tasks
|
||||
self.drList.removeContextTask()
|
||||
# Turn off camera fly
|
||||
self.cameraControl.disableMouseFly()
|
||||
# Turn off object manipulation
|
||||
self.manipulationControl.disableManipulation()
|
||||
self.disableKeyEvents()
|
||||
self.disableModifierEvents()
|
||||
self.disableMouseEvents()
|
||||
self.ignore('DH_LoadingComplete')
|
||||
# Kill tasks
|
||||
taskMgr.remove('flashNodePath')
|
||||
taskMgr.remove('hideDirectMessage')
|
||||
taskMgr.remove('hideDirectMessageLater')
|
||||
# Set flag
|
||||
self.fEnabled = 0
|
||||
|
||||
def minimumConfiguration(self):
|
||||
# Remove context task
|
||||
self.drList.removeContextTask()
|
||||
# Turn off camera fly
|
||||
self.cameraControl.disableMouseFly()
|
||||
# Ignore keyboard and action events
|
||||
self.disableKeyEvents()
|
||||
self.disableActionEvents()
|
||||
# But let mouse events pass through
|
||||
self.enableMouseEvents()
|
||||
self.enableModifierEvents()
|
||||
|
||||
def oobe(self):
|
||||
# If oobeMode was never set, set it to false and create the
|
||||
# structures we need to implement OOBE.
|
||||
try:
|
||||
self.oobeMode
|
||||
except:
|
||||
self.oobeMode = 0
|
||||
|
||||
self.oobeCamera = hidden.attachNewNode('oobeCamera')
|
||||
|
||||
self.oobeVis = loader.loadModelOnce('models/misc/camera')
|
||||
if self.oobeVis:
|
||||
self.oobeVis.node().setFinal(1)
|
||||
|
||||
if self.oobeMode:
|
||||
# Position a target point to lerp the oobe camera to
|
||||
self.cameraControl.camManipRef.iPosHpr(self.trueCamera)
|
||||
t = self.oobeCamera.lerpPosHpr(
|
||||
Point3(0), Vec3(0), 2.0,
|
||||
other = self.cameraControl.camManipRef,
|
||||
task = 'manipulateCamera',
|
||||
blendType = 'easeInOut')
|
||||
# When move is done, switch to oobe mode
|
||||
t.uponDeath = self.endOOBE
|
||||
else:
|
||||
# Place camera marker at true camera location
|
||||
self.oobeVis.reparentTo(self.trueCamera)
|
||||
# Remove any transformation on the models arc
|
||||
self.oobeVis.clearMat()
|
||||
# Make oobeCamera be a sibling of wherever camera is now.
|
||||
cameraParent = self.camera.getParent()
|
||||
# Prepare oobe camera
|
||||
self.oobeCamera.reparentTo(cameraParent)
|
||||
self.oobeCamera.iPosHpr(self.trueCamera)
|
||||
# Put camera under new oobe camera
|
||||
base.cam.reparentTo(self.oobeCamera)
|
||||
# Position a target point to lerp the oobe camera to
|
||||
self.cameraControl.camManipRef.setPos(
|
||||
self.trueCamera, Vec3(-2,-20, 5))
|
||||
self.cameraControl.camManipRef.lookAt(self.trueCamera)
|
||||
t = self.oobeCamera.lerpPosHpr(
|
||||
Point3(0), Vec3(0), 2.0,
|
||||
other = self.cameraControl.camManipRef,
|
||||
task = 'manipulateCamera',
|
||||
blendType = 'easeInOut')
|
||||
# When move is done, switch to oobe mode
|
||||
t.uponDeath = self.beginOOBE
|
||||
|
||||
def beginOOBE(self, state):
|
||||
# Make sure we've reached our final destination
|
||||
self.oobeCamera.iPosHpr(self.cameraControl.camManipRef)
|
||||
self.camera = self.oobeCamera
|
||||
self.oobeMode = 1
|
||||
|
||||
def endOOBE(self, state):
|
||||
# Make sure we've reached our final destination
|
||||
self.oobeCamera.iPosHpr(self.trueCamera)
|
||||
# Disable OOBE mode.
|
||||
base.cam.reparentTo(self.trueCamera)
|
||||
self.camera = self.trueCamera
|
||||
# Get rid of ancillary node paths
|
||||
self.oobeVis.reparentTo(hidden)
|
||||
self.oobeCamera.reparentTo(hidden)
|
||||
self.oobeMode = 0
|
||||
|
||||
def destroy(self):
|
||||
self.disable()
|
||||
|
||||
def reset(self):
|
||||
self.enable()
|
||||
|
||||
# EVENT FUNCTIONS
|
||||
def enableModifierEvents(self):
|
||||
for event in self.modifierEvents:
|
||||
self.accept(event, self.inputHandler, [event])
|
||||
|
||||
def enableKeyEvents(self):
|
||||
for event in self.keyEvents:
|
||||
self.accept(event, self.inputHandler, [event])
|
||||
|
||||
def enableMouseEvents(self):
|
||||
for event in self.mouseEvents:
|
||||
self.accept(event, self.inputHandler, [event])
|
||||
|
||||
def disableModifierEvents(self):
|
||||
for event in self.modifierEvents:
|
||||
self.ignore(event)
|
||||
|
||||
def disableKeyEvents(self):
|
||||
for event in self.keyEvents:
|
||||
self.ignore(event)
|
||||
|
||||
def disableMouseEvents(self):
|
||||
for event in self.mouseEvents:
|
||||
self.ignore(event)
|
||||
|
||||
def inputHandler(self, input):
|
||||
# Deal with keyboard and mouse input
|
||||
if input == 'mouse1-up':
|
||||
messenger.send('DIRECT-mouse1Up')
|
||||
if SEditor.widget.fActive:
|
||||
messenger.send('shift-f')
|
||||
elif input.find('mouse1') != -1:
|
||||
modifiers = self.getModifiers(input, 'mouse1')
|
||||
messenger.send('DIRECT-mouse1', sentArgs = [modifiers])
|
||||
elif input == 'mouse2-up':
|
||||
messenger.send('DIRECT-mouse2Up')
|
||||
if SEditor.widget.fActive:
|
||||
messenger.send('shift-f')
|
||||
elif input.find('mouse2') != -1:
|
||||
modifiers = self.getModifiers(input, 'mouse2')
|
||||
messenger.send('DIRECT-mouse2', sentArgs = [modifiers])
|
||||
elif input == 'mouse3-up':
|
||||
messenger.send('DIRECT-mouse3Up')
|
||||
if SEditor.widget.fActive:
|
||||
messenger.send('shift-f')
|
||||
elif input.find('mouse3') != -1:
|
||||
modifiers = self.getModifiers(input, 'mouse3')
|
||||
messenger.send('DIRECT-mouse3', sentArgs = [modifiers])
|
||||
elif input == 'shift':
|
||||
self.fShift = 1
|
||||
elif input == 'shift-up':
|
||||
self.fShift = 0
|
||||
elif input == 'control':
|
||||
self.fControl = 1
|
||||
elif input == 'control-up':
|
||||
self.fControl = 0
|
||||
elif input == 'alt':
|
||||
self.fAlt = 1
|
||||
elif input == 'alt-up':
|
||||
self.fAlt = 0
|
||||
elif input == 'page_up':
|
||||
self.upAncestry()
|
||||
elif input == 'page_down':
|
||||
self.downAncestry()
|
||||
elif input == 'escape':
|
||||
self.deselectAll()
|
||||
elif input == 'delete':
|
||||
taskMgr.remove('followSelectedNodePath')
|
||||
#self.removeAllSelected()
|
||||
messenger.send('SGE_Remove',[None])
|
||||
self.deselectAll()
|
||||
elif input == 'v':
|
||||
messenger.send('SEditor-ToggleWidgetVis')
|
||||
self.toggleWidgetVis()
|
||||
if SEditor.widget.fActive:
|
||||
messenger.send('shift-f')
|
||||
elif input == 'b':
|
||||
messenger.send('SEditor-ToggleBackface')
|
||||
base.toggleBackface()
|
||||
#elif input == 'control-f':
|
||||
# self.flash(last)
|
||||
elif input == 'shift-l':
|
||||
self.cameraControl.toggleCOALock()
|
||||
elif input == 'o':
|
||||
self.oobe()
|
||||
elif input == 'p':
|
||||
if self.selected.last:
|
||||
self.setActiveParent(self.selected.last)
|
||||
elif input == 'r':
|
||||
# Do wrt reparent
|
||||
if self.selected.last:
|
||||
self.reparent(self.selected.last, fWrt = 1)
|
||||
elif input == 'shift-r':
|
||||
# Do regular reparent
|
||||
if self.selected.last:
|
||||
self.reparent(self.selected.last)
|
||||
elif input == 's':
|
||||
if self.selected.last:
|
||||
self.select(self.selected.last)
|
||||
elif input == 't':
|
||||
messenger.send('SEditor-ToggleTexture')
|
||||
base.toggleTexture()
|
||||
elif input == 'shift-a':
|
||||
self.selected.toggleVisAll()
|
||||
elif input == 'w':
|
||||
messenger.send('SEditor-ToggleWireframe')
|
||||
base.toggleWireframe()
|
||||
elif (input == '[') or (input == '{'):
|
||||
self.undo()
|
||||
elif (input == ']') or (input == '}'):
|
||||
self.redo()
|
||||
|
||||
|
||||
def getModifiers(self, input, base):
|
||||
modifiers = DIRECT_NO_MOD
|
||||
modifierString = input[: input.find(base)]
|
||||
if modifierString.find('shift') != -1:
|
||||
modifiers |= DIRECT_SHIFT_MOD
|
||||
if modifierString.find('control') != -1:
|
||||
modifiers |= DIRECT_CONTROL_MOD
|
||||
if modifierString.find('alt') != -1:
|
||||
modifiers |= DIRECT_ALT_MOD
|
||||
return modifiers
|
||||
|
||||
def gotShift(self, modifiers):
|
||||
return modifiers & DIRECT_SHIFT_MOD
|
||||
|
||||
def gotControl(self, modifiers):
|
||||
return modifiers & DIRECT_CONTROL_MOD
|
||||
|
||||
def gotAlt(self, modifiers):
|
||||
return modifiers & DIRECT_ALT_MOD
|
||||
|
||||
def select(self, nodePath, fMultiSelect = 0, fResetAncestry = 1, callback=False):
|
||||
dnp = self.selected.select(nodePath, fMultiSelect)
|
||||
if dnp:
|
||||
messenger.send('DIRECT_preSelectNodePath', [dnp])
|
||||
if fResetAncestry:
|
||||
# Update ancestry
|
||||
self.ancestry = dnp.getAncestors()
|
||||
self.ancestry.reverse()
|
||||
self.ancestryIndex = 0
|
||||
# Update the selectedNPReadout
|
||||
self.selectedNPReadout.reparentTo(aspect2d)
|
||||
self.selectedNPReadout.setText(
|
||||
'Selected:' + dnp.getName())
|
||||
# Show the manipulation widget
|
||||
self.widget.showWidget()
|
||||
# Update camera controls coa to this point
|
||||
# Coa2Camera = Coa2Dnp * Dnp2Camera
|
||||
mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(self.camera)
|
||||
row = mCoa2Camera.getRow(3)
|
||||
coa = Vec3(row[0], row[1], row[2])
|
||||
self.cameraControl.updateCoa(coa)
|
||||
# Adjust widgets size
|
||||
# This uses the additional scaling factor used to grow and
|
||||
# shrink the widget
|
||||
self.widget.setScalingFactor(dnp.getRadius())
|
||||
# Spawn task to have object handles follow the selected object
|
||||
taskMgr.remove('followSelectedNodePath')
|
||||
t = Task.Task(self.followSelectedNodePathTask)
|
||||
t.dnp = dnp
|
||||
taskMgr.add(t, 'followSelectedNodePath')
|
||||
# Send an message marking the event
|
||||
messenger.send('DIRECT_selectedNodePath', [dnp])
|
||||
if callback:
|
||||
messenger.send('se_selectedNodePath', [dnp, False])
|
||||
else:
|
||||
messenger.send('se_selectedNodePath', [dnp])
|
||||
|
||||
self.upAncestry()
|
||||
|
||||
if SEditor.widget.fActive:
|
||||
messenger.send('shift-f')
|
||||
|
||||
def followSelectedNodePathTask(self, state):
|
||||
mCoa2Render = state.dnp.mCoa2Dnp * state.dnp.getMat(render)
|
||||
decomposeMatrix(mCoa2Render,
|
||||
self.scale,self.hpr,self.pos,
|
||||
CSDefault)
|
||||
self.widget.setPosHpr(self.pos,self.hpr)
|
||||
return Task.cont
|
||||
|
||||
def deselect(self, nodePath):
|
||||
dnp = self.selected.deselect(nodePath)
|
||||
if dnp:
|
||||
# Hide the manipulation widget
|
||||
self.widget.hideWidget()
|
||||
self.selectedNPReadout.reparentTo(hidden)
|
||||
self.selectedNPReadout.setText(' ')
|
||||
taskMgr.remove('followSelectedNodePath')
|
||||
self.ancestry = []
|
||||
# Send an message marking the event
|
||||
messenger.send('DIRECT_deselectedNodePath', [dnp])
|
||||
|
||||
def deselectAll(self):
|
||||
self.selected.deselectAll()
|
||||
# Hide the manipulation widget
|
||||
self.widget.hideWidget()
|
||||
self.selectedNPReadout.reparentTo(hidden)
|
||||
self.selectedNPReadout.setText(' ')
|
||||
taskMgr.remove('followSelectedNodePath')
|
||||
messenger.send('se_deselectedAll')
|
||||
|
||||
def setActiveParent(self, nodePath = None):
|
||||
# Record new parent
|
||||
self.activeParent = nodePath
|
||||
# Update the activeParentReadout
|
||||
self.activeParentReadout.reparentTo(aspect2d)
|
||||
self.activeParentReadout.setText(
|
||||
'Active Reparent Target:' + nodePath.getName())
|
||||
# Alert everyone else
|
||||
self.activeParentReadout.show()
|
||||
|
||||
def reparent(self, nodePath = None, fWrt = 0):
|
||||
if (nodePath and self.activeParent and
|
||||
self.isNotCycle(nodePath, self.activeParent)):
|
||||
oldParent = nodePath.getParent()
|
||||
if fWrt:
|
||||
nodePath.wrtReparentTo(self.activeParent)
|
||||
else:
|
||||
nodePath.reparentTo(self.activeParent)
|
||||
# Alert everyone else
|
||||
messenger.send('DIRECT_reparent',
|
||||
[nodePath, oldParent, self.activeParent])
|
||||
messenger.send('SGE_Update Explorer',[render])
|
||||
self.activeParentReadout.hide()
|
||||
|
||||
|
||||
def isNotCycle(self, nodePath, parent):
|
||||
if nodePath.id() == parent.id():
|
||||
print 'DIRECT.reparent: Invalid parent'
|
||||
return 0
|
||||
elif parent.hasParent():
|
||||
return self.isNotCycle(nodePath, parent.getParent())
|
||||
else:
|
||||
return 1
|
||||
|
||||
def fitOnNodePath(self, nodePath = 'None Given'):
|
||||
if nodePath == 'None Given':
|
||||
# If nothing specified, try selected node path
|
||||
nodePath = self.selected.last
|
||||
SEditor.select(nodePath)
|
||||
def fitTask(state, self = self):
|
||||
self.cameraControl.fitOnWidget()
|
||||
return Task.done
|
||||
taskMgr.doMethodLater(0.1, fitTask, 'manipulateCamera')
|
||||
|
||||
def isolate(self, nodePath = 'None Given'):
|
||||
""" Show a node path and hide its siblings """
|
||||
# First kill the flashing task to avoid complications
|
||||
taskMgr.remove('flashNodePath')
|
||||
# Use currently selected node path if node selected
|
||||
if nodePath == 'None Given':
|
||||
nodePath = self.selected.last
|
||||
# Do we have a node path?
|
||||
if nodePath:
|
||||
# Yes, show everything in level
|
||||
self.showAllDescendants(nodePath.getParent())
|
||||
# Now hide all of this node path's siblings
|
||||
nodePath.hideSiblings()
|
||||
|
||||
def toggleVis(self, nodePath = 'None Given'):
|
||||
""" Toggle visibility of node path """
|
||||
# First kill the flashing task to avoid complications
|
||||
taskMgr.remove('flashNodePath')
|
||||
if nodePath == 'None Given':
|
||||
# If nothing specified, try selected node path
|
||||
nodePath = self.selected.last
|
||||
if nodePath:
|
||||
# Now toggle node path's visibility state
|
||||
nodePath.toggleVis()
|
||||
|
||||
def removeNodePath(self, nodePath = 'None Given'):
|
||||
if nodePath == 'None Given':
|
||||
# If nothing specified, try selected node path
|
||||
nodePath = self.selected.last
|
||||
if nodePath:
|
||||
nodePath.remove()
|
||||
|
||||
def removeAllSelected(self):
|
||||
self.selected.removeAll()
|
||||
|
||||
def showAllDescendants(self, nodePath = render):
|
||||
""" Show the level and its descendants """
|
||||
nodePath.showAllDescendants()
|
||||
nodePath.hideCS()
|
||||
|
||||
def upAncestry(self):
|
||||
if self.ancestry:
|
||||
l = len(self.ancestry)
|
||||
i = self.ancestryIndex + 1
|
||||
if i < l:
|
||||
np = self.ancestry[i]
|
||||
name = np.getName()
|
||||
if i>0:
|
||||
type = self.ancestry[i-1].node().getType().getName()
|
||||
else:
|
||||
type = self.ancestry[0].node().getType().getName()
|
||||
|
||||
ntype = np.node().getType().getName()
|
||||
if (name != 'render') and (name != 'renderTop')and(self.checkTypeNameForAncestry(type, ntype)):
|
||||
self.ancestryIndex = i
|
||||
self.select(np, 0, 0, True)
|
||||
|
||||
def checkTypeNameForAncestry(self, type, nextType ):
|
||||
if (type=='ModelRoot'):
|
||||
if (nextType=='AmbientLight')or(nextType=='PointLight')or(nextType=='DirectionalLight')or(nextType=='Spotlight'):
|
||||
return True
|
||||
return False
|
||||
elif (type=='ModelNode'):
|
||||
if (nextType=='ModelNode'):
|
||||
return True
|
||||
return False
|
||||
elif (type=='CollisionNode'):
|
||||
return False
|
||||
elif (type=='ActorNode'):
|
||||
return False
|
||||
elif (type=='AmbientLight')or(type=='PointLight')or(type=='DirectionalLight')or(type=='Spotlight'):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def downAncestry(self):
|
||||
if self.ancestry:
|
||||
l = len(self.ancestry)
|
||||
i = self.ancestryIndex - 1
|
||||
if i >= 0:
|
||||
np = self.ancestry[i]
|
||||
name = np.getName()
|
||||
if (name != 'render') and (name != 'renderTop'):
|
||||
self.ancestryIndex = i
|
||||
self.select(np, 0, 0, True)
|
||||
|
||||
|
||||
def getAndSetName(self, nodePath):
|
||||
""" Prompt user for new node path name """
|
||||
from tkSimpleDialog import askstring
|
||||
newName = askstring('Node Path: ' + nodePath.getName(),
|
||||
'Enter new name:')
|
||||
if newName:
|
||||
nodePath.setName(newName)
|
||||
messenger.send('DIRECT_nodePathSetName', [nodePath, newName])
|
||||
|
||||
# UNDO REDO FUNCTIONS
|
||||
def pushUndo(self, nodePathList, fResetRedo = 1):
|
||||
# Assemble group of changes
|
||||
undoGroup = []
|
||||
for nodePath in nodePathList:
|
||||
t = nodePath.getTransform()
|
||||
undoGroup.append([nodePath, t])
|
||||
# Now record group
|
||||
self.undoList.append(undoGroup)
|
||||
# Truncate list
|
||||
self.undoList = self.undoList[-25:]
|
||||
# Alert anyone who cares
|
||||
messenger.send('DIRECT_pushUndo')
|
||||
if fResetRedo and (nodePathList != []):
|
||||
self.redoList = []
|
||||
messenger.send('DIRECT_redoListEmpty')
|
||||
|
||||
def popUndoGroup(self):
|
||||
# Get last item
|
||||
undoGroup = self.undoList[-1]
|
||||
# Strip last item off of undo list
|
||||
self.undoList = self.undoList[:-1]
|
||||
# Update state of undo button
|
||||
if not self.undoList:
|
||||
messenger.send('DIRECT_undoListEmpty')
|
||||
# Return last item
|
||||
return undoGroup
|
||||
|
||||
def pushRedo(self, nodePathList):
|
||||
# Assemble group of changes
|
||||
redoGroup = []
|
||||
for nodePath in nodePathList:
|
||||
t = nodePath.getTransform()
|
||||
redoGroup.append([nodePath, t])
|
||||
# Now record redo group
|
||||
self.redoList.append(redoGroup)
|
||||
# Truncate list
|
||||
self.redoList = self.redoList[-25:]
|
||||
# Alert anyone who cares
|
||||
messenger.send('DIRECT_pushRedo')
|
||||
|
||||
def popRedoGroup(self):
|
||||
# Get last item
|
||||
redoGroup = self.redoList[-1]
|
||||
# Strip last item off of redo list
|
||||
self.redoList = self.redoList[:-1]
|
||||
# Update state of redo button
|
||||
if not self.redoList:
|
||||
messenger.send('DIRECT_redoListEmpty')
|
||||
# Return last item
|
||||
return redoGroup
|
||||
|
||||
def undo(self):
|
||||
if self.undoList:
|
||||
# Get last item off of redo list
|
||||
undoGroup = self.popUndoGroup()
|
||||
# Record redo information
|
||||
nodePathList = map(lambda x: x[0], undoGroup)
|
||||
self.pushRedo(nodePathList)
|
||||
# Now undo xform for group
|
||||
for pose in undoGroup:
|
||||
# Undo xform
|
||||
pose[0].setTransform(pose[1])
|
||||
# Alert anyone who cares
|
||||
messenger.send('DIRECT_undo')
|
||||
|
||||
def redo(self):
|
||||
if self.redoList:
|
||||
# Get last item off of redo list
|
||||
redoGroup = self.popRedoGroup()
|
||||
# Record undo information
|
||||
nodePathList = map(lambda x: x[0], redoGroup)
|
||||
self.pushUndo(nodePathList, fResetRedo = 0)
|
||||
# Redo xform
|
||||
for pose in redoGroup:
|
||||
pose[0].setTransform(pose[1])
|
||||
# Alert anyone who cares
|
||||
messenger.send('DIRECT_redo')
|
||||
|
||||
# UTILITY FUNCTIONS
|
||||
def message(self, text):
|
||||
taskMgr.remove('hideDirectMessage')
|
||||
taskMgr.remove('hideDirectMessageLater')
|
||||
self.directMessageReadout.reparentTo(aspect2d)
|
||||
self.directMessageReadout.setText(text)
|
||||
self.hideDirectMessageLater()
|
||||
|
||||
def hideDirectMessageLater(self):
|
||||
taskMgr.doMethodLater(3.0, self.hideDirectMessage, 'hideDirectMessage')
|
||||
|
||||
def hideDirectMessage(self, state):
|
||||
self.directMessageReadout.reparentTo(hidden)
|
||||
return Task.done
|
||||
|
||||
def useObjectHandles(self):
|
||||
self.widget = self.manipulationControl.objectHandles
|
||||
self.widget.reparentTo(SEditor.group)
|
||||
|
||||
def hideSelectedNPReadout(self):
|
||||
self.selectedNPReadout.reparentTo(hidden)
|
||||
|
||||
def hideActiveParentReadout(self):
|
||||
self.activeParentReadout.reparentTo(hidden)
|
||||
|
||||
def toggleWidgetVis(self):
|
||||
self.widget.toggleWidget()
|
||||
|
||||
def setCOAMode(self, mode):
|
||||
self.coaMode = mode
|
||||
|
||||
def isEnabled(self):
|
||||
return self.fEnabled
|
||||
|
||||
def addUnpickable(self, item):
|
||||
for iRay in self.iRayList:
|
||||
iRay.addUnpickable(item)
|
||||
|
||||
def removeUnpickable(self, item):
|
||||
for iRay in self.iRayList:
|
||||
iRay.removeUnpickable(item)
|
||||
|
||||
def toggleAutoCamera(self):
|
||||
self.enableAutoCamera = (self.enableAutoCamera+1)%2
|
||||
if self.enableAutoCamera==1:
|
||||
self.accept('DH_LoadingComplete', self.autoCameraMove)
|
||||
else:
|
||||
self.ignore('DH_LoadingComplete')
|
||||
return
|
||||
|
||||
def autoCameraMove(self, nodePath):
|
||||
time = 1
|
||||
node = DirectNodePath(nodePath)
|
||||
radius = node.getRadius()
|
||||
center = node.getCenter()
|
||||
node.dehighlight()
|
||||
posB = base.camera.getPos()
|
||||
hprB = base.camera.getHpr()
|
||||
posE = Point3((radius*-1.41)+center.getX(), (radius*-1.41)+center.getY(), (radius*1.41)+center.getZ())
|
||||
hprE = Point3(-45, -38, 0)
|
||||
print posB, hprB
|
||||
print posE, hprE
|
||||
posInterval1 = base.camera.posInterval(time, posE, bakeInStart = 1)
|
||||
posInterval2 = base.camera.posInterval(time, posB, bakeInStart = 1)
|
||||
|
||||
hprInterval1 = base.camera.hprInterval(time, hprE, bakeInStart = 1)
|
||||
hprInterval2 = base.camera.hprInterval(time, hprB, bakeInStart = 1)
|
||||
|
||||
parallel1 = Parallel(posInterval1, hprInterval1)
|
||||
parallel2 = Parallel(posInterval2, hprInterval2)
|
||||
|
||||
Sequence(Wait(7), parallel1, Wait(1), parallel2).start()
|
||||
|
||||
return
|
||||
|
||||
|
||||
class DisplayRegionContext(DirectObject):
|
||||
regionCount = 0
|
||||
def __init__(self, cam):
|
||||
self.cam = cam
|
||||
self.camNode = self.cam.node()
|
||||
self.camLens = self.camNode.getLens()
|
||||
# set lens change callback
|
||||
changeEvent = 'dr%d-change-event' % DisplayRegionContext.regionCount
|
||||
DisplayRegionContext.regionCount += 1
|
||||
self.camLens.setChangeEvent(changeEvent)
|
||||
self.accept(changeEvent, self.camUpdate)
|
||||
self.iRay = SelectionRay(self.cam)
|
||||
self.nearVec = Vec3(0)
|
||||
self.mouseX = 0.0
|
||||
self.mouseY = 0.0
|
||||
# A Camera node can have more than one display region
|
||||
# associated with it. Here I assume that there is only
|
||||
# one display region per camera, since we are defining a
|
||||
# display region on a per-camera basis. See note in
|
||||
# DisplayRegionList.__init__()
|
||||
try:
|
||||
self.dr = self.camNode.getDr(0)
|
||||
except:
|
||||
self.dr = self.camNode.getDisplayRegion(0)
|
||||
left = self.dr.getLeft()
|
||||
right = self.dr.getRight()
|
||||
bottom = self.dr.getBottom()
|
||||
top = self.dr.getTop()
|
||||
self.originX = left+right-1
|
||||
self.originY = top+bottom-1
|
||||
self.scaleX = 1.0/(right-left)
|
||||
self.scaleY = 1.0/(top-bottom)
|
||||
self.setOrientation()
|
||||
self.camUpdate()
|
||||
|
||||
def __getitem__(self,key):
|
||||
return self.__dict__[key]
|
||||
|
||||
def setOrientation(self):
|
||||
# MRM This assumes orientation is set on transform above cam
|
||||
hpr = self.cam.getHpr()
|
||||
if hpr[2] < 135 and hpr[2]>45 or hpr[2]>225 and hpr[2]<315:
|
||||
self.isSideways = 1
|
||||
elif hpr[2] > -135 and hpr[2] < -45 or hpr[2] < -225 and hpr[2] > -315:
|
||||
self.isSideways = 1
|
||||
else:
|
||||
self.isSideways = 0
|
||||
|
||||
# The following take into consideration sideways displays
|
||||
def getHfov(self):
|
||||
if self.isSideways:
|
||||
return self.camLens.getVfov()
|
||||
else:
|
||||
return self.camLens.getHfov()
|
||||
|
||||
def getVfov(self):
|
||||
if self.isSideways:
|
||||
return self.camLens.getHfov()
|
||||
else:
|
||||
return self.camLens.getVfov()
|
||||
|
||||
def setHfov(self,hfov):
|
||||
if self.isSideways:
|
||||
self.camLens.setFov(self.camLens.getHfov(), hfov)
|
||||
else:
|
||||
self.camLens.setFov(hfov, self.camLens.getVfov())
|
||||
|
||||
def setVfov(self,vfov):
|
||||
if self.isSideways:
|
||||
self.camLens.setFov(vfov, self.camLens.getVfov())
|
||||
else:
|
||||
self.camLens.setFov(self.camLens.getHfov(), vfov)
|
||||
|
||||
def setFov(self,hfov,vfov):
|
||||
if self.isSideways:
|
||||
self.camLens.setFov(vfov, hfov)
|
||||
else:
|
||||
self.camLens.setFov(hfov, vfov)
|
||||
|
||||
def getWidth(self):
|
||||
prop = base.win.getProperties()
|
||||
if prop.hasSize():
|
||||
return prop.getXSize()
|
||||
else:
|
||||
return 640
|
||||
|
||||
def getHeight(self):
|
||||
prop = base.win.getProperties()
|
||||
if prop.hasSize():
|
||||
return prop.getYSize()
|
||||
else:
|
||||
return 480
|
||||
|
||||
def camUpdate(self, lens = None):
|
||||
# Window Data
|
||||
self.near = self.camLens.getNear()
|
||||
self.far = self.camLens.getFar()
|
||||
self.fovH = self.camLens.getHfov()
|
||||
self.fovV = self.camLens.getVfov()
|
||||
self.nearWidth = math.tan(deg2Rad(self.fovH * 0.5)) * self.near * 2.0
|
||||
self.nearHeight = math.tan(deg2Rad(self.fovV * 0.5)) * self.near * 2.0
|
||||
self.left = -self.nearWidth * 0.5
|
||||
self.right = self.nearWidth * 0.5
|
||||
self.top = self.nearHeight * 0.5
|
||||
self.bottom = -self.nearHeight * 0.5
|
||||
|
||||
def mouseUpdate(self):
|
||||
# Mouse Data
|
||||
# Last frame
|
||||
self.mouseLastX = self.mouseX
|
||||
self.mouseLastY = self.mouseY
|
||||
# Values for this frame
|
||||
# This ranges from -1 to 1
|
||||
if (base.mouseWatcherNode.hasMouse()):
|
||||
self.mouseX = base.mouseWatcherNode.getMouseX()
|
||||
self.mouseY = base.mouseWatcherNode.getMouseY()
|
||||
self.mouseX = (self.mouseX-self.originX)*self.scaleX
|
||||
self.mouseY = (self.mouseY-self.originY)*self.scaleY
|
||||
# Delta percent of window the mouse moved
|
||||
self.mouseDeltaX = self.mouseX - self.mouseLastX
|
||||
self.mouseDeltaY = self.mouseY - self.mouseLastY
|
||||
self.nearVec.set((self.nearWidth*0.5) * self.mouseX,
|
||||
self.near,
|
||||
(self.nearHeight*0.5) * self.mouseY)
|
||||
|
||||
class DisplayRegionList(DirectObject):
|
||||
def __init__(self):
|
||||
self.displayRegionList = []
|
||||
i = 0
|
||||
# Things are funky if we are oobe
|
||||
if (hasattr(base, 'oobeMode') and base.oobeMode):
|
||||
# assume we only have one cam at this point
|
||||
drc = DisplayRegionContext(base.cam)
|
||||
self.displayRegionList.append(drc)
|
||||
else:
|
||||
# MRM: Doesn't properly handle multiple camera groups anymore
|
||||
# Assumes everything is under main camera
|
||||
|
||||
# This is following the old way of setting up
|
||||
# display regions. A display region is set up for
|
||||
# each camera node in the scene graph. This was done
|
||||
# so that only display regions in the scene graph are
|
||||
# considered. The right way to do this is to set up
|
||||
# a display region for each real display region, and then
|
||||
# keep track of which are currently active (e.g. use a flag)
|
||||
# processing only them.
|
||||
for camIndex in range(len(base.camList)):
|
||||
cam = base.camList[camIndex]
|
||||
if cam.getName()=='<noname>':
|
||||
cam.setName('Camera%d' % camIndex)
|
||||
drc = DisplayRegionContext(cam)
|
||||
self.displayRegionList.append(drc)
|
||||
|
||||
self.accept("DIRECT-mouse1",self.mouseUpdate)
|
||||
self.accept("DIRECT-mouse2",self.mouseUpdate)
|
||||
self.accept("DIRECT-mouse3",self.mouseUpdate)
|
||||
self.accept("DIRECT-mouse1Up",self.mouseUpdate)
|
||||
self.accept("DIRECT-mouse2Up",self.mouseUpdate)
|
||||
self.accept("DIRECT-mouse3Up",self.mouseUpdate)
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.displayRegionList[index]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.displayRegionList)
|
||||
|
||||
def updateContext(self):
|
||||
self.contextTask(None)
|
||||
|
||||
def setNearFar(self, near, far):
|
||||
for dr in self.displayRegionList:
|
||||
dr.camLens.setNearFar(near, far)
|
||||
|
||||
def setNear(self, near):
|
||||
for dr in self.displayRegionList:
|
||||
dr.camLens.setNear(near)
|
||||
|
||||
def setFar(self, far):
|
||||
for dr in self.displayRegionList:
|
||||
dr.camLens.setFar(far)
|
||||
|
||||
def setFov(self, hfov, vfov):
|
||||
for dr in self.displayRegionList:
|
||||
dr.setFov(hfov, vfov)
|
||||
|
||||
def setHfov(self, fov):
|
||||
for dr in self.displayRegionList:
|
||||
dr.setHfov(fov)
|
||||
|
||||
def setVfov(self, fov):
|
||||
for dr in self.displayRegionList:
|
||||
dr.setVfov(fov)
|
||||
|
||||
def mouseUpdate(self, modifiers = DIRECT_NO_MOD):
|
||||
for dr in self.displayRegionList:
|
||||
dr.mouseUpdate()
|
||||
SEditor.dr = self.getCurrentDr()
|
||||
|
||||
def getCurrentDr(self):
|
||||
for dr in self.displayRegionList:
|
||||
if (dr.mouseX >= -1.0 and dr.mouseX <= 1.0 and
|
||||
dr.mouseY >= -1.0 and dr.mouseY <= 1.0):
|
||||
return dr
|
||||
return self.displayRegionList[0]
|
||||
|
||||
def start(self):
|
||||
# First shutdown any existing task
|
||||
self.stop()
|
||||
# Start a new context task
|
||||
self.spawnContextTask()
|
||||
|
||||
def stop(self):
|
||||
# Kill the existing context task
|
||||
taskMgr.remove('DIRECTContextTask')
|
||||
|
||||
def spawnContextTask(self):
|
||||
taskMgr.add(self.contextTask, 'DIRECTContextTask')
|
||||
|
||||
def removeContextTask(self):
|
||||
taskMgr.remove('DIRECTContextTask')
|
||||
|
||||
def contextTask(self, state):
|
||||
# Window Data
|
||||
self.mouseUpdate()
|
||||
# hack to test movement
|
||||
return Task.cont
|
||||
|
||||
# Create one
|
||||
#__builtins__['direct'] = base.direct = DirectSession()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
418
build/nirai/panda3d/contrib/src/sceneeditor/seTree.py
Normal file
418
build/nirai/panda3d/contrib/src/sceneeditor/seTree.py
Normal file
|
@ -0,0 +1,418 @@
|
|||
#################################################################
|
||||
# seTree.py
|
||||
# Originally from Tree.py
|
||||
# Altered by Yi-Hong Lin, yihhongl@andrew.cmu.edu, 2004
|
||||
#
|
||||
# This class actually decides the behavior of the sceneGraphExplorer
|
||||
# You might feel it realy looks like the original one, but we actually did a lots of change in it.
|
||||
# such as, when selection happend in other place, such as picking directly inside the scene. or,
|
||||
# when user removed something by hot key.
|
||||
# The rename process has also been changed. It won't be rename in here anymore.
|
||||
# Instead, here we will send out a message to sceneEditor to reaname the target.
|
||||
#
|
||||
#################################################################
|
||||
|
||||
import os, sys, string, Pmw, Tkinter
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from Tkinter import IntVar, Menu, PhotoImage, Label, Frame, Entry
|
||||
from pandac.PandaModules import *
|
||||
|
||||
# Initialize icon directory
|
||||
ICONDIR = getModelPath().findFile(Filename('icons')).toOsSpecific()
|
||||
if not os.path.isdir(ICONDIR):
|
||||
raise RuntimeError, "can't find DIRECT icon directory (%s)" % `ICONDIR`
|
||||
|
||||
class TreeNode:
|
||||
|
||||
def __init__(self, canvas, parent, item, menuList = []):
|
||||
self.canvas = canvas
|
||||
self.parent = parent
|
||||
self.item = item
|
||||
self.state = 'collapsed'
|
||||
self.selected = 0
|
||||
self.children = {}
|
||||
self.kidKeys = []
|
||||
self.x = self.y = None
|
||||
self.iconimages = {} # cache of PhotoImage instances for icons
|
||||
self.menuList = menuList
|
||||
self.menuVar = IntVar()
|
||||
self.menuVar.set(0)
|
||||
self._popupMenu = None
|
||||
self.image_id = None
|
||||
if self.menuList:
|
||||
if self.menuList[-1] == 'Separator':
|
||||
self.menuList = self.menuList[:-1]
|
||||
self._popupMenu = Menu(self.canvas, tearoff = 0)
|
||||
for i in range(len(self.menuList)):
|
||||
item = self.menuList[i]
|
||||
if item == 'Separator':
|
||||
self._popupMenu.add_separator()
|
||||
else:
|
||||
self._popupMenu.add_radiobutton(
|
||||
label = item,
|
||||
variable = self.menuVar,
|
||||
value = i,
|
||||
indicatoron = 0,
|
||||
command = self.popupMenuCommand)
|
||||
|
||||
def destroy(self):
|
||||
for key in self.kidKeys:
|
||||
c = self.children[key]
|
||||
del self.children[key]
|
||||
c.destroy()
|
||||
self.parent = None
|
||||
|
||||
def geticonimage(self, name):
|
||||
try:
|
||||
return self.iconimages[name]
|
||||
except KeyError:
|
||||
pass
|
||||
file, ext = os.path.splitext(name)
|
||||
ext = ext or ".gif"
|
||||
fullname = os.path.join(ICONDIR, file + ext)
|
||||
image = PhotoImage(master=self.canvas, file=fullname)
|
||||
self.iconimages[name] = image
|
||||
return image
|
||||
|
||||
def select(self, event=None):
|
||||
if self.selected:
|
||||
return
|
||||
self.deselectall()
|
||||
self.selected = 1
|
||||
if self.parent != None:
|
||||
if self.parent.state == 'expanded':
|
||||
self.canvas.delete(self.image_id)
|
||||
self.drawicon()
|
||||
self.drawtext()
|
||||
self.item.OnSelect(event)
|
||||
|
||||
def deselect(self, event=None):
|
||||
if not self.selected:
|
||||
return
|
||||
self.selected = 0
|
||||
if self.parent != None:
|
||||
if self.parent.state == 'expanded':
|
||||
self.canvas.delete(self.image_id)
|
||||
self.drawicon()
|
||||
self.drawtext()
|
||||
|
||||
def deselectall(self):
|
||||
if self.parent:
|
||||
self.parent.deselectall()
|
||||
else:
|
||||
self.deselecttree()
|
||||
|
||||
def deselecttree(self):
|
||||
if self.selected:
|
||||
self.deselect()
|
||||
for key in self.kidKeys:
|
||||
child = self.children[key]
|
||||
child.deselecttree()
|
||||
|
||||
def flip(self, event=None):
|
||||
if self.state == 'expanded':
|
||||
self.collapse()
|
||||
else:
|
||||
self.expand()
|
||||
self.item.OnDoubleClick()
|
||||
return "break"
|
||||
|
||||
def popupMenu(self, event=None):
|
||||
if self._popupMenu:
|
||||
self._popupMenu.post(event.widget.winfo_pointerx(),
|
||||
event.widget.winfo_pointery())
|
||||
return "break"
|
||||
|
||||
def popupMenuCommand(self):
|
||||
command = self.menuList[self.menuVar.get()]
|
||||
self.item.MenuCommand(command)
|
||||
if self.parent and (command != 'Update Explorer'):
|
||||
# Update parent to try to keep explorer up to date
|
||||
self.parent.update()
|
||||
|
||||
def expand(self, event=None):
|
||||
if not self.item.IsExpandable():
|
||||
return
|
||||
if self.state != 'expanded':
|
||||
self.state = 'expanded'
|
||||
self.update()
|
||||
self.view()
|
||||
|
||||
def collapse(self, event=None):
|
||||
if self.state != 'collapsed':
|
||||
self.state = 'collapsed'
|
||||
self.update()
|
||||
|
||||
def view(self):
|
||||
top = self.y - 2
|
||||
bottom = self.lastvisiblechild().y + 17
|
||||
height = bottom - top
|
||||
visible_top = self.canvas.canvasy(0)
|
||||
visible_height = self.canvas.winfo_height()
|
||||
visible_bottom = self.canvas.canvasy(visible_height)
|
||||
if visible_top <= top and bottom <= visible_bottom:
|
||||
return
|
||||
x0, y0, x1, y1 = self.canvas._getints(self.canvas['scrollregion'])
|
||||
if top >= visible_top and height <= visible_height:
|
||||
fraction = top + height - visible_height
|
||||
else:
|
||||
fraction = top
|
||||
fraction = float(fraction) / y1
|
||||
self.canvas.yview_moveto(fraction)
|
||||
|
||||
def reveal(self):
|
||||
# Make sure all parent nodes are marked as expanded
|
||||
parent = self.parent
|
||||
while parent:
|
||||
if parent.state == 'collapsed':
|
||||
parent.state = 'expanded'
|
||||
parent = parent.parent
|
||||
else:
|
||||
break
|
||||
# Redraw tree accordingly
|
||||
self.update()
|
||||
# Bring this item into view
|
||||
self.view()
|
||||
|
||||
def lastvisiblechild(self):
|
||||
if self.kidKeys and self.state == 'expanded':
|
||||
return self.children[self.kidKeys[-1]].lastvisiblechild()
|
||||
else:
|
||||
return self
|
||||
|
||||
def update(self):
|
||||
if self.parent:
|
||||
self.parent.update()
|
||||
else:
|
||||
oldcursor = self.canvas['cursor']
|
||||
self.canvas['cursor'] = "watch"
|
||||
self.canvas.update()
|
||||
self.canvas.delete(Tkinter.ALL) # XXX could be more subtle
|
||||
self.draw(7, 2)
|
||||
x0, y0, x1, y1 = self.canvas.bbox(Tkinter.ALL)
|
||||
self.canvas.configure(scrollregion=(0, 0, x1, y1))
|
||||
self.canvas['cursor'] = oldcursor
|
||||
|
||||
def draw(self, x, y):
|
||||
# XXX This hard-codes too many geometry constants!
|
||||
self.x, self.y = x, y
|
||||
self.drawicon()
|
||||
self.drawtext()
|
||||
if self.state != 'expanded':
|
||||
return y+17
|
||||
# draw children
|
||||
sublist = self.item._GetSubList()
|
||||
if not sublist:
|
||||
# IsExpandable() was mistaken; that's allowed
|
||||
return y+17
|
||||
self.kidKeys = []
|
||||
for item in sublist:
|
||||
key = item.GetKey()
|
||||
if self.children.has_key(key):
|
||||
child = self.children[key]
|
||||
else:
|
||||
child = TreeNode(self.canvas, self, item, self.menuList)
|
||||
self.children[key] = child
|
||||
self.kidKeys.append(key)
|
||||
# Remove unused children
|
||||
for key in self.children.keys():
|
||||
if key not in self.kidKeys:
|
||||
del(self.children[key])
|
||||
cx = x+20
|
||||
cy = y+17
|
||||
cylast = 0
|
||||
for key in self.kidKeys:
|
||||
child = self.children[key]
|
||||
cylast = cy
|
||||
self.canvas.create_line(x+9, cy+7, cx, cy+7, fill="gray50")
|
||||
cy = child.draw(cx, cy)
|
||||
if child.item.IsExpandable():
|
||||
if child.state == 'expanded':
|
||||
iconname = "minusnode"
|
||||
callback = child.collapse
|
||||
else:
|
||||
iconname = "plusnode"
|
||||
callback = child.expand
|
||||
image = self.geticonimage(iconname)
|
||||
id = self.canvas.create_image(x+9, cylast+7, image=image)
|
||||
# XXX This leaks bindings until canvas is deleted:
|
||||
self.canvas.tag_bind(id, "<1>", callback)
|
||||
self.canvas.tag_bind(id, "<Double-1>", lambda x: None)
|
||||
id = self.canvas.create_line(x+9, y+10, x+9, cylast+7,
|
||||
##stipple="gray50", # XXX Seems broken in Tk 8.0.x
|
||||
fill="gray50")
|
||||
self.canvas.tag_lower(id) # XXX .lower(id) before Python 1.5.2
|
||||
return cy
|
||||
|
||||
def drawicon(self):
|
||||
if self.selected:
|
||||
imagename = (self.item.GetSelectedIconName() or
|
||||
self.item.GetIconName() or
|
||||
"openfolder")
|
||||
else:
|
||||
imagename = self.item.GetIconName() or "folder"
|
||||
image = self.geticonimage(imagename)
|
||||
id = self.canvas.create_image(self.x, self.y, anchor="nw", image=image)
|
||||
self.image_id = id
|
||||
self.canvas.tag_bind(id, "<1>", self.select)
|
||||
self.canvas.tag_bind(id, "<Double-1>", self.flip)
|
||||
self.canvas.tag_bind(id, "<3>", self.popupMenu)
|
||||
|
||||
def drawtext(self, text=None):
|
||||
textx = self.x+20-1
|
||||
texty = self.y-1
|
||||
labeltext = self.item.GetLabelText()
|
||||
if labeltext:
|
||||
id = self.canvas.create_text(textx, texty, anchor="nw",
|
||||
text=labeltext)
|
||||
self.canvas.tag_bind(id, "<1>", self.select)
|
||||
self.canvas.tag_bind(id, "<Double-1>", self.flip)
|
||||
x0, y0, x1, y1 = self.canvas.bbox(id)
|
||||
textx = max(x1, 200) + 10
|
||||
if text==None:
|
||||
text = self.item.GetText() or "<no text>"
|
||||
try:
|
||||
self.entry
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
self.edit_finish()
|
||||
try:
|
||||
label = self.label
|
||||
except AttributeError:
|
||||
# padding carefully selected (on Windows) to match Entry widget:
|
||||
self.label = Label(self.canvas, text=text, bd=0, padx=2, pady=2)
|
||||
if self.selected:
|
||||
self.label.configure(fg="white", bg="darkblue")
|
||||
else:
|
||||
fg = self.item.GetTextFg()
|
||||
self.label.configure(fg=fg, bg="white")
|
||||
id = self.canvas.create_window(textx, texty,
|
||||
anchor="nw", window=self.label)
|
||||
self.label.bind("<1>", self.select_or_edit)
|
||||
self.label.bind("<Double-1>", self.flip)
|
||||
self.label.bind("<3>", self.popupMenu)
|
||||
# Update text if necessary
|
||||
if text != self.label['text']:
|
||||
self.label['text'] = text
|
||||
self.text_id = id
|
||||
|
||||
def select_or_edit(self, event=None):
|
||||
if self.selected and self.item.IsEditable():
|
||||
text = self.item.GetTextForEdit()
|
||||
self.label['text'] = text
|
||||
self.drawtext(text)
|
||||
self.edit(event)
|
||||
else:
|
||||
self.select(event)
|
||||
|
||||
def edit(self, event=None):
|
||||
self.entry = Entry(self.label, bd=0, highlightthickness=1, width=0)
|
||||
self.entry.insert(0, self.label['text'])
|
||||
self.entry.selection_range(0, Tkinter.END)
|
||||
self.entry.pack(ipadx=5)
|
||||
self.entry.focus_set()
|
||||
self.entry.bind("<Return>", self.edit_finish)
|
||||
self.entry.bind("<Escape>", self.edit_cancel)
|
||||
|
||||
def edit_finish(self, event=None):
|
||||
try:
|
||||
entry = self.entry
|
||||
del self.entry
|
||||
except AttributeError:
|
||||
return
|
||||
text = entry.get()
|
||||
entry.destroy()
|
||||
if text and text != self.item.GetText():
|
||||
self.item.SetText(text)
|
||||
text = self.item.GetText()
|
||||
self.label['text'] = text
|
||||
self.drawtext()
|
||||
self.canvas.focus_set()
|
||||
|
||||
def edit_cancel(self, event=None):
|
||||
self.drawtext()
|
||||
self.canvas.focus_set()
|
||||
|
||||
def find(self, searchKey):
|
||||
# Search for a node who's key matches the given key
|
||||
# Is it this node
|
||||
if searchKey == self.item.GetKey():
|
||||
return self
|
||||
# Nope, check the children
|
||||
sublist = self.item._GetSubList()
|
||||
for item in sublist:
|
||||
key = item.GetKey()
|
||||
# Use existing child or create new TreeNode if none exists
|
||||
if self.children.has_key(key):
|
||||
child = self.children[key]
|
||||
else:
|
||||
child = TreeNode(self.canvas, self, item, self.menuList)
|
||||
# Update local list of children and keys
|
||||
self.children[key] = child
|
||||
self.kidKeys.append(key)
|
||||
# See if node is child (or one of child's descendants)
|
||||
retVal = child.find(searchKey)
|
||||
if retVal:
|
||||
return retVal
|
||||
# Not here
|
||||
return None
|
||||
|
||||
class TreeItem:
|
||||
|
||||
"""Abstract class representing tree items.
|
||||
|
||||
Methods should typically be overridden, otherwise a default action
|
||||
is used.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""Constructor. Do whatever you need to do."""
|
||||
|
||||
def GetText(self):
|
||||
"""Return text string to display."""
|
||||
|
||||
def GetTextFg(self):
|
||||
return "black"
|
||||
|
||||
def GetLabelText(self):
|
||||
"""Return label text string to display in front of text (if any)."""
|
||||
|
||||
def IsExpandable(self):
|
||||
"""Return whether there are subitems."""
|
||||
return 1
|
||||
|
||||
def _GetSubList(self):
|
||||
"""Do not override! Called by TreeNode."""
|
||||
if not self.IsExpandable():
|
||||
return []
|
||||
sublist = self.GetSubList()
|
||||
return sublist
|
||||
|
||||
def IsEditable(self):
|
||||
"""Return whether the item's text may be edited."""
|
||||
|
||||
def SetText(self, text):
|
||||
"""Change the item's text (if it is editable)."""
|
||||
|
||||
def GetIconName(self):
|
||||
"""Return name of icon to be displayed normally."""
|
||||
|
||||
def GetSelectedIconName(self):
|
||||
"""Return name of icon to be displayed when selected."""
|
||||
|
||||
def GetSubList(self):
|
||||
"""Return list of items forming sublist."""
|
||||
|
||||
def OnDoubleClick(self):
|
||||
"""Called on a double-click on the item."""
|
||||
|
||||
def OnSelect(self):
|
||||
"""Called when item selected."""
|
||||
|
||||
def GetTextForEdit(self):
|
||||
"""Called before editting the item."""
|
||||
|
||||
|
||||
|
9
build/nirai/panda3d/direct/.gitignore
vendored
Normal file
9
build/nirai/panda3d/direct/.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
*.pyc
|
||||
*.pyo
|
||||
/__init__.py
|
||||
# These are files that are generated within the source tree by the
|
||||
# ppremake system.
|
||||
Makefile
|
||||
pp.dep
|
||||
/built/
|
||||
Opt?-*
|
60
build/nirai/panda3d/direct/Package.pp
Normal file
60
build/nirai/panda3d/direct/Package.pp
Normal file
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// Package.pp
|
||||
//
|
||||
// This file defines certain configuration variables that are to be
|
||||
// written into the various make scripts. It is processed by ppremake
|
||||
// (along with the Sources.pp files in each of the various
|
||||
// directories) to generate build scripts appropriate to each
|
||||
// environment.
|
||||
//
|
||||
// This is the package-specific file, which should be at the top of
|
||||
// every source hierarchy. It generally gets the ball rolling, and is
|
||||
// responsible for explicitly including all of the relevent Config.pp
|
||||
// files.
|
||||
|
||||
// What is the name and version of this source tree?
|
||||
#if $[eq $[PACKAGE],]
|
||||
#define PACKAGE direct
|
||||
#define VERSION 0.80
|
||||
#endif
|
||||
|
||||
|
||||
// Where should we find the PANDA source directory?
|
||||
#if $[PANDA_SOURCE]
|
||||
#define PANDA_SOURCE $[unixfilename $[PANDA_SOURCE]]
|
||||
#elif $[or $[CTPROJS],$[PANDA]]
|
||||
// If we are presently attached, use the environment variable.
|
||||
#define PANDA_SOURCE $[unixfilename $[PANDA]]
|
||||
#if $[eq $[PANDA],]
|
||||
#error You seem to be attached to some trees, but not PANDA!
|
||||
#endif
|
||||
#else
|
||||
// Otherwise, if we are not attached, we guess that the source is a
|
||||
// sibling directory to this source root.
|
||||
#define PANDA_SOURCE $[standardize $[TOPDIR]/../panda]
|
||||
#endif
|
||||
|
||||
// Where should we install DIRECT?
|
||||
#if $[DIRECT_INSTALL]
|
||||
#define DIRECT_INSTALL $[unixfilename $[DIRECT_INSTALL]]
|
||||
#elif $[CTPROJS]
|
||||
#set DIRECT $[unixfilename $[DIRECT]]
|
||||
#define DIRECT_INSTALL $[DIRECT]/built
|
||||
#if $[eq $[DIRECT],]
|
||||
#error You seem to be attached to some trees, but not DIRECT!
|
||||
#endif
|
||||
#else
|
||||
#defer DIRECT_INSTALL $[unixfilename $[INSTALL_DIR]]
|
||||
#endif
|
||||
|
||||
// Also get the PANDA Package file and everything that includes.
|
||||
#if $[not $[isfile $[PANDA_SOURCE]/Package.pp]]
|
||||
#printvar PANDA_SOURCE
|
||||
#error PANDA source directory not found from direct! Are you attached properly?
|
||||
#endif
|
||||
|
||||
#include $[PANDA_SOURCE]/Package.pp
|
||||
|
||||
// Define the inter-tree dependencies.
|
||||
#define NEEDS_TREES panda $[NEEDS_TREES]
|
||||
#define DEPENDABLE_HEADER_DIRS $[DEPENDABLE_HEADER_DIRS] $[PANDA_INSTALL]/include
|
11
build/nirai/panda3d/direct/Sources.pp
Normal file
11
build/nirai/panda3d/direct/Sources.pp
Normal file
|
@ -0,0 +1,11 @@
|
|||
// This is the toplevel directory for a package.
|
||||
|
||||
#define DIR_TYPE toplevel
|
||||
|
||||
#define SAMPLE_SOURCE_FILE src/directbase/directbase.cxx
|
||||
#define REQUIRED_TREES dtool panda
|
||||
|
||||
#define EXTRA_DIST \
|
||||
Sources.pp Config.pp Package.pp
|
||||
|
||||
#define PYTHON_PACKAGE 1
|
7
build/nirai/panda3d/direct/metalibs/Sources.pp
Normal file
7
build/nirai/panda3d/direct/metalibs/Sources.pp
Normal file
|
@ -0,0 +1,7 @@
|
|||
// This is a group directory: a directory level above a number of
|
||||
// source subdirectories.
|
||||
|
||||
#define DIR_TYPE group
|
||||
|
||||
// The metalibs directory always depends on the src directory.
|
||||
#define DEPENDS src
|
32
build/nirai/panda3d/direct/metalibs/direct/Sources.pp
Normal file
32
build/nirai/panda3d/direct/metalibs/direct/Sources.pp
Normal file
|
@ -0,0 +1,32 @@
|
|||
// DIR_TYPE "metalib" indicates we are building a shared library that
|
||||
// consists mostly of references to other shared libraries. Under
|
||||
// Windows, this directly produces a DLL (as opposed to the regular
|
||||
// src libraries, which don't produce anything but a pile of OBJ files
|
||||
// under Windows).
|
||||
|
||||
#define DIR_TYPE metalib
|
||||
#define BUILDING_DLL BUILDING_DIRECT
|
||||
#define USE_PACKAGES native_net
|
||||
|
||||
#define COMPONENT_LIBS \
|
||||
p3directbase p3dcparser p3showbase p3deadrec p3directd p3interval p3distributed p3motiontrail p3http
|
||||
|
||||
#define OTHER_LIBS \
|
||||
panda:m \
|
||||
pandaexpress:m \
|
||||
p3parametrics:c \
|
||||
p3interrogatedb:c p3dconfig:c p3dtoolconfig:m \
|
||||
p3dtoolutil:c p3dtoolbase:c p3dtool:m \
|
||||
p3express:c p3pstatclient:c p3prc:c p3pandabase:c p3linmath:c \
|
||||
p3putil:c p3display:c p3event:c p3pgraph:c p3pgraphnodes:c \
|
||||
p3gsgbase:c p3gobj:c p3mathutil:c \
|
||||
p3downloader:c p3pnmimage:c p3chan:c \
|
||||
p3pipeline:c p3cull:c \
|
||||
$[if $[HAVE_NET],p3net:c] $[if $[WANT_NATIVE_NET],p3nativenet:c]
|
||||
|
||||
#begin metalib_target
|
||||
#define TARGET p3direct
|
||||
|
||||
#define SOURCES direct.cxx
|
||||
#end metalib_target
|
||||
|
9
build/nirai/panda3d/direct/metalibs/direct/direct.cxx
Normal file
9
build/nirai/panda3d/direct/metalibs/direct/direct.cxx
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Filename: direct.cxx
|
||||
// Created by: drose (18May00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This is a dummy file whose sole purpose is to give the compiler
|
||||
// something to compile when making libdirect.so in NO_DEFER mode,
|
||||
// which generates an empty library that itself links with all the
|
||||
// other shared libraries that make up libdirect.
|
4
build/nirai/panda3d/direct/src/Sources.pp
Normal file
4
build/nirai/panda3d/direct/src/Sources.pp
Normal file
|
@ -0,0 +1,4 @@
|
|||
// This is a group directory: a directory level above a number of
|
||||
// source subdirectories.
|
||||
|
||||
#define DIR_TYPE group
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue