Merged changes in the trunk up to revision 25613.

This commit is contained in:
2009-12-29 21:46:36 +00:00
294 changed files with 19336 additions and 17280 deletions

View File

@@ -47,18 +47,21 @@ if MACOSX_ARCHITECTURE == 'ppc':
# CC = 'gcc-3.3' # CC = 'gcc-3.3'
# CXX = 'g++-3.3' # CXX = 'g++-3.3'
MAC_MIN_VERS = '10.4' MAC_MIN_VERS = '10.4'
MACOSX_DEPLOYMENT_TARGET = '10.4'
MACOSX_SDK='/Developer/SDKs/MacOSX10.4u.sdk' MACOSX_SDK='/Developer/SDKs/MacOSX10.4u.sdk'
LCGDIR = '#../lib/darwin-8.0.0-powerpc' LCGDIR = '#../lib/darwin-8.0.0-powerpc'
CC = 'gcc-4.0' CC = 'gcc-4.0'
CXX = 'g++-4.0' CXX = 'g++-4.0'
elif MACOSX_ARCHITECTURE == 'i386': elif MACOSX_ARCHITECTURE == 'i386':
MAC_MIN_VERS = '10.4' MAC_MIN_VERS = '10.4'
MACOSX_DEPLOYMENT_TARGET = '10.4'
MACOSX_SDK='/Developer/SDKs/MacOSX10.4u.sdk' MACOSX_SDK='/Developer/SDKs/MacOSX10.4u.sdk'
LCGDIR = '#../lib/darwin-8.x.i386' LCGDIR = '#../lib/darwin-8.x.i386'
CC = 'gcc-4.0' CC = 'gcc-4.0'
CXX = 'g++-4.0' CXX = 'g++-4.0'
else : else :
MAC_MIN_VERS = '10.5' MAC_MIN_VERS = '10.5'
MACOSX_DEPLOYMENT_TARGET = '10.5'
MACOSX_SDK='/Developer/SDKs/MacOSX10.5.sdk' MACOSX_SDK='/Developer/SDKs/MacOSX10.5.sdk'
LCGDIR = '#../lib/darwin-9.x.universal' LCGDIR = '#../lib/darwin-9.x.universal'
CC = 'gcc-4.2' CC = 'gcc-4.2'

View File

@@ -793,7 +793,7 @@ btSoftBody* btSoftBodyHelpers::CreateEllipsoid(btSoftBodyWorldInfo& worldInfo,c
// //
btSoftBody* btSoftBodyHelpers::CreateFromTriMesh(btSoftBodyWorldInfo& worldInfo,const btScalar* vertices, btSoftBody* btSoftBodyHelpers::CreateFromTriMesh(btSoftBodyWorldInfo& worldInfo,const btScalar* vertices,
const int* triangles, const int* triangles,
int ntriangles) int ntriangles, bool randomizeConstraints)
{ {
int maxidx=0; int maxidx=0;
int i,j,ni; int i,j,ni;
@@ -828,14 +828,16 @@ btSoftBody* btSoftBodyHelpers::CreateFromTriMesh(btSoftBodyWorldInfo& worldInfo
#undef IDX #undef IDX
psb->appendFace(idx[0],idx[1],idx[2]); psb->appendFace(idx[0],idx[1],idx[2]);
} }
// don't randomize now, let's give a chance to the application to set face data if (randomizeConstraints)
//psb->randomizeConstraints(); {
psb->randomizeConstraints();
}
return(psb); return(psb);
} }
// //
btSoftBody* btSoftBodyHelpers::CreateFromConvexHull(btSoftBodyWorldInfo& worldInfo, const btVector3* vertices, btSoftBody* btSoftBodyHelpers::CreateFromConvexHull(btSoftBodyWorldInfo& worldInfo, const btVector3* vertices,
int nvertices) int nvertices, bool randomizeConstraints)
{ {
HullDesc hdsc(QF_TRIANGLES,nvertices,vertices); HullDesc hdsc(QF_TRIANGLES,nvertices,vertices);
HullResult hres; HullResult hres;
@@ -855,6 +857,9 @@ btSoftBody* btSoftBodyHelpers::CreateFromConvexHull(btSoftBodyWorldInfo& worldI
psb->appendFace(idx[0],idx[1],idx[2]); psb->appendFace(idx[0],idx[1],idx[2]);
} }
hlib.ReleaseResult(hres); hlib.ReleaseResult(hres);
psb->randomizeConstraints(); if (randomizeConstraints)
{
psb->randomizeConstraints();
}
return(psb); return(psb);
} }

View File

@@ -109,11 +109,13 @@ struct btSoftBodyHelpers
static btSoftBody* CreateFromTriMesh( btSoftBodyWorldInfo& worldInfo, static btSoftBody* CreateFromTriMesh( btSoftBodyWorldInfo& worldInfo,
const btScalar* vertices, const btScalar* vertices,
const int* triangles, const int* triangles,
int ntriangles); int ntriangles,
bool randomizeConstraints = true);
/* Create from convex-hull */ /* Create from convex-hull */
static btSoftBody* CreateFromConvexHull( btSoftBodyWorldInfo& worldInfo, static btSoftBody* CreateFromConvexHull( btSoftBodyWorldInfo& worldInfo,
const btVector3* vertices, const btVector3* vertices,
int nvertices); int nvertices,
bool randomizeConstraints = true);
}; };
#endif //SOFT_BODY_HELPERS_H #endif //SOFT_BODY_HELPERS_H

View File

@@ -40,11 +40,6 @@ IF(WITH_OPENAL)
SET(INC ${INC} OpenAL ${OPENAL_INCLUDE_DIR}) SET(INC ${INC} OpenAL ${OPENAL_INCLUDE_DIR})
FILE(GLOB OPENALSRC OpenAL/*.cpp) FILE(GLOB OPENALSRC OpenAL/*.cpp)
ADD_DEFINITIONS(-DWITH_OPENAL) ADD_DEFINITIONS(-DWITH_OPENAL)
STRING(REGEX MATCH ".*ramework.*" FRAMEWORK ${OPENAL_INCLUDE_DIR})
IF(FRAMEWORK)
ADD_DEFINITIONS(-DAPPLE_FRAMEWORK_FIX)
ENDIF(FRAMEWORK)
ENDIF(WITH_OPENAL) ENDIF(WITH_OPENAL)
IF(WITH_JACK) IF(WITH_JACK)
@@ -59,6 +54,12 @@ IF(WITH_SNDFILE)
ADD_DEFINITIONS(-DWITH_SNDFILE) ADD_DEFINITIONS(-DWITH_SNDFILE)
ENDIF(WITH_SNDFILE) ENDIF(WITH_SNDFILE)
SET(SRC ${SRC} ${FFMPEGSRC} ${SNDFILESRC} ${SDLSRC} ${OPENALSRC} ${JACKSRC}) IF(WITH_FFTW3)
SET(INC ${INC} fftw ${FFTW3_INC})
FILE(GLOB FFTW3SRC fftw/*.cpp)
ADD_DEFINITIONS(-DWITH_FFTW3)
ENDIF(WITH_FFTW3)
SET(SRC ${SRC} ${FFMPEGSRC} ${SNDFILESRC} ${FFTW3SRC} ${SDLSRC} ${OPENALSRC} ${JACKSRC})
BLENDERLIB(bf_audaspace "${SRC}" "${INC}") BLENDERLIB(bf_audaspace "${SRC}" "${INC}")

View File

@@ -38,7 +38,7 @@ private:
/** /**
* The loop count. * The loop count.
*/ */
float m_loop; int m_loop;
public: public:
/** /**

View File

@@ -0,0 +1,45 @@
/*
* $Id$
*
* ***** BEGIN LGPL LICENSE BLOCK *****
*
* Copyright 2009 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* AudaSpace is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AudaSpace is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with AudaSpace. If not, see <http://www.gnu.org/licenses/>.
*
* ***** END LGPL LICENSE BLOCK *****
*/
#include "AUD_RectifyFactory.h"
#include "AUD_RectifyReader.h"
AUD_RectifyFactory::AUD_RectifyFactory(AUD_IFactory* factory) :
AUD_EffectFactory(factory) {}
AUD_RectifyFactory::AUD_RectifyFactory() :
AUD_EffectFactory(0) {}
AUD_IReader* AUD_RectifyFactory::createReader()
{
AUD_IReader* reader = getReader();
if(reader != 0)
{
reader = new AUD_RectifyReader(reader); AUD_NEW("reader")
}
return reader;
}

View File

@@ -0,0 +1,51 @@
/*
* $Id$
*
* ***** BEGIN LGPL LICENSE BLOCK *****
*
* Copyright 2009 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* AudaSpace is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AudaSpace is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with AudaSpace. If not, see <http://www.gnu.org/licenses/>.
*
* ***** END LGPL LICENSE BLOCK *****
*/
#ifndef AUD_RECTIFYFACTORY
#define AUD_RECTIFYFACTORY
#include "AUD_EffectFactory.h"
/**
* This factory rectifies another factory.
*/
class AUD_RectifyFactory : public AUD_EffectFactory
{
public:
/**
* Creates a new rectify factory.
* \param factory The input factory.
*/
AUD_RectifyFactory(AUD_IFactory* factory = 0);
/**
* Creates a new rectify factory.
*/
AUD_RectifyFactory();
virtual AUD_IReader* createReader();
};
#endif //AUD_RECTIFYFACTORY

View File

@@ -0,0 +1,82 @@
/*
* $Id$
*
* ***** BEGIN LGPL LICENSE BLOCK *****
*
* Copyright 2009 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* AudaSpace is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AudaSpace is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with AudaSpace. If not, see <http://www.gnu.org/licenses/>.
*
* ***** END LGPL LICENSE BLOCK *****
*/
#include "AUD_RectifyReader.h"
#include "AUD_Buffer.h"
#include <cstring>
AUD_RectifyReader::AUD_RectifyReader(AUD_IReader* reader) :
AUD_EffectReader(reader)
{
int bigendian = 1;
bigendian = (((char*)&bigendian)[0]) ? 0: 1; // 1 if Big Endian
switch(m_reader->getSpecs().format)
{
case AUD_FORMAT_S16:
m_rectify = AUD_rectify<int16_t>;
break;
case AUD_FORMAT_S32:
m_rectify = AUD_rectify<int32_t>;
break;
case AUD_FORMAT_FLOAT32:
m_rectify = AUD_rectify<float>;
break;
case AUD_FORMAT_FLOAT64:
m_rectify = AUD_rectify<double>;
break;
case AUD_FORMAT_U8:
m_rectify = AUD_rectify_u8;
break;
case AUD_FORMAT_S24:
m_rectify = bigendian ? AUD_rectify_s24_be : AUD_rectify_s24_le;
break;
default:
delete m_reader;
AUD_THROW(AUD_ERROR_READER);
}
m_buffer = new AUD_Buffer(); AUD_NEW("buffer")
}
AUD_RectifyReader::~AUD_RectifyReader()
{
delete m_buffer; AUD_DELETE("buffer")
}
void AUD_RectifyReader::read(int & length, sample_t* & buffer)
{
sample_t* buf;
AUD_Specs specs = m_reader->getSpecs();
m_reader->read(length, buf);
if(m_buffer->getSize() < length*AUD_SAMPLE_SIZE(specs))
m_buffer->resize(length*AUD_SAMPLE_SIZE(specs));
buffer = m_buffer->getBuffer();
m_rectify(buffer, buf, length * specs.channels);
}

View File

@@ -0,0 +1,65 @@
/*
* $Id$
*
* ***** BEGIN LGPL LICENSE BLOCK *****
*
* Copyright 2009 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* AudaSpace is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AudaSpace is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with AudaSpace. If not, see <http://www.gnu.org/licenses/>.
*
* ***** END LGPL LICENSE BLOCK *****
*/
#ifndef AUD_RECTIFYREADER
#define AUD_RECTIFYREADER
#include "AUD_EffectReader.h"
#include "AUD_ConverterFunctions.h"
class AUD_Buffer;
/**
* This class reads another reader and rectifies it.
*/
class AUD_RectifyReader : public AUD_EffectReader
{
private:
/**
* The playback buffer.
*/
AUD_Buffer *m_buffer;
/**
* Rectifying function.
*/
AUD_rectify_f m_rectify;
public:
/**
* Creates a new rectify reader.
* \param reader The reader to read from.
* \exception AUD_Exception Thrown if the reader specified is NULL.
*/
AUD_RectifyReader(AUD_IReader* reader);
/**
* Destroys the reader.
*/
virtual ~AUD_RectifyReader();
virtual void read(int & length, sample_t* & buffer);
};
#endif //AUD_RECTIFYREADER

View File

@@ -56,6 +56,10 @@ ifeq ($(WITH_SNDFILE),true)
DIRS += sndfile DIRS += sndfile
endif endif
ifeq ($(WITH_FFTW3),true)
DIRS += fftw
endif
include nan_subdirs.mk include nan_subdirs.mk
install: $(ALL_OR_DEBUG) install: $(ALL_OR_DEBUG)
@@ -80,6 +84,10 @@ ifeq ($(WITH_SNDFILE),true)
@../tools/cpifdiff.sh $(DIR)/$(DEBUG_DIR)libaud_sndfile.a $(NAN_AUDASPACE)/lib/$(DEBUG_DIR) @../tools/cpifdiff.sh $(DIR)/$(DEBUG_DIR)libaud_sndfile.a $(NAN_AUDASPACE)/lib/$(DEBUG_DIR)
endif endif
ifeq ($(WITH_FFTW3),true)
@../tools/cpifdiff.sh $(DIR)/$(DEBUG_DIR)libaud_fftw.a $(NAN_AUDASPACE)/lib/$(DEBUG_DIR)
endif
ifeq ($(OS),darwin) ifeq ($(OS),darwin)
ranlib $(NAN_AUDASPACE)/lib/$(DEBUG_DIR)libaudaspace.a ranlib $(NAN_AUDASPACE)/lib/$(DEBUG_DIR)libaudaspace.a
ranlib $(NAN_AUDASPACE)/lib/$(DEBUG_DIR)libaud_src.a ranlib $(NAN_AUDASPACE)/lib/$(DEBUG_DIR)libaud_src.a
@@ -102,5 +110,9 @@ ifeq ($(WITH_SNDFILE),true)
ranlib $(NAN_AUDASPACE)/lib/$(DEBUG_DIR)libaud_sndfile.a ranlib $(NAN_AUDASPACE)/lib/$(DEBUG_DIR)libaud_sndfile.a
endif endif
ifeq ($(WITH_FFTW3),true)
ranlib $(NAN_AUDASPACE)/lib/$(DEBUG_DIR)libaud_fftw.a
endif
endif endif
@../tools/cpifdiff.sh intern/*.h $(NAN_AUDASPACE)/include/ @../tools/cpifdiff.sh intern/*.h $(NAN_AUDASPACE)/include/

View File

@@ -31,4 +31,9 @@ if env['WITH_BF_SNDFILE']:
incs += ' sndfile ' + env['BF_SNDFILE_INC'] incs += ' sndfile ' + env['BF_SNDFILE_INC']
defs.append('WITH_SNDFILE') defs.append('WITH_SNDFILE')
if env['WITH_BF_FFTW3']:
sources += env.Glob('fftw/*.cpp')
incs += ' fftw ' + env['BF_FFTW3_INC']
defs.append('WITH_FFTW3')
env.BlenderLib ('bf_audaspace', sources, Split(incs), defs, libtype=['intern','player'], priority = [25,215] ) env.BlenderLib ('bf_audaspace', sources, Split(incs), defs, libtype=['intern','player'], priority = [25,215] )

View File

@@ -0,0 +1,79 @@
/*
* $Id$
*
* ***** BEGIN LGPL LICENSE BLOCK *****
*
* Copyright 2009 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* AudaSpace is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AudaSpace is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with AudaSpace. If not, see <http://www.gnu.org/licenses/>.
*
* ***** END LGPL LICENSE BLOCK *****
*/
#include "AUD_BandPassFactory.h"
#include "AUD_BandPassReader.h"
AUD_BandPassFactory::AUD_BandPassFactory(AUD_IFactory* factory, float low,
float high) :
AUD_EffectFactory(factory),
m_low(low),
m_high(high) {}
AUD_BandPassFactory::AUD_BandPassFactory(float low, float high) :
AUD_EffectFactory(0),
m_low(low),
m_high(high) {}
float AUD_BandPassFactory::getLow()
{
return m_low;
}
float AUD_BandPassFactory::getHigh()
{
return m_high;
}
void AUD_BandPassFactory::setLow(float low)
{
m_low = low;
}
void AUD_BandPassFactory::setHigh(float high)
{
m_high = high;
}
AUD_IReader* AUD_BandPassFactory::createReader()
{
AUD_IReader* reader = getReader();
if(reader != 0)
{
if(reader->getSpecs().format == AUD_FORMAT_FLOAT32)
{
reader = new AUD_BandPassReader(reader, m_low, m_high);
AUD_NEW("reader")
}
else
{
delete reader; AUD_DELETE("reader")
return 0;
}
}
return reader;
}

View File

@@ -0,0 +1,88 @@
/*
* $Id$
*
* ***** BEGIN LGPL LICENSE BLOCK *****
*
* Copyright 2009 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* AudaSpace is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AudaSpace is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with AudaSpace. If not, see <http://www.gnu.org/licenses/>.
*
* ***** END LGPL LICENSE BLOCK *****
*/
#ifndef AUD_BANDPASSFACTORY
#define AUD_BANDPASSFACTORY
#include "AUD_EffectFactory.h"
/**
* This factory creates a band pass filter for a sound wave.
*/
class AUD_BandPassFactory : public AUD_EffectFactory
{
private:
/**
* The lowest frequency to be passed.
*/
float m_low;
/**
* The highest frequency to be passed.
*/
float m_high;
public:
/**
* Creates a new band pass factory.
* \param factory The input factory.
* \param low The lowest passed frequency.
* \param high The highest passed frequency.
*/
AUD_BandPassFactory(AUD_IFactory* factory, float low, float high);
/**
* Creates a new band pass factory.
* \param low The lowest passed frequency.
* \param high The highest passed frequency.
*/
AUD_BandPassFactory(float low, float high);
/**
* Returns the lowest passed frequency.
*/
float getLow();
/**
* Returns the highest passed frequency.
*/
float getHigh();
/**
* Sets the lowest passed frequency.
* \param low The lowest passed frequency.
*/
void setLow(float low);
/**
* Sets the highest passed frequency.
* \param high The highest passed frequency.
*/
void setHigh(float hight);
virtual AUD_IReader* createReader();
};
#endif //AUD_BANDPASSFACTORY

View File

@@ -0,0 +1,126 @@
/*
* $Id$
*
* ***** BEGIN LGPL LICENSE BLOCK *****
*
* Copyright 2009 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* AudaSpace is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AudaSpace is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with AudaSpace. If not, see <http://www.gnu.org/licenses/>.
*
* ***** END LGPL LICENSE BLOCK *****
*/
#include "AUD_BandPassReader.h"
#include "AUD_Buffer.h"
#include <cstring>
#include <stdio.h>
AUD_BandPassReader::AUD_BandPassReader(AUD_IReader* reader, float low,
float high) :
AUD_EffectReader(reader), m_low(low), m_high(high)
{
m_buffer = new AUD_Buffer(); AUD_NEW("buffer")
m_in = new AUD_Buffer(); AUD_NEW("buffer")
m_out = new AUD_Buffer(); AUD_NEW("buffer")
m_length = 0;
}
AUD_BandPassReader::~AUD_BandPassReader()
{
if(m_length != 0)
{
fftw_destroy_plan(m_forward);
fftw_destroy_plan(m_backward);
}
delete m_buffer; AUD_DELETE("buffer")
delete m_in; AUD_DELETE("buffer")
delete m_out; AUD_DELETE("buffer")
}
AUD_ReaderType AUD_BandPassReader::getType()
{
return m_reader->getType();
}
void AUD_BandPassReader::read(int & length, sample_t* & buffer)
{
AUD_Specs specs = m_reader->getSpecs();
m_reader->read(length, buffer);
if(length > 0)
{
if(length * AUD_SAMPLE_SIZE(specs) > m_buffer->getSize())
m_buffer->resize(length * AUD_SAMPLE_SIZE(specs));
if(length != m_length)
{
if(m_length != 0)
{
fftw_destroy_plan(m_forward);
fftw_destroy_plan(m_backward);
}
m_length = length;
printf("WINDOW: %d\n", m_length);
if(m_length * sizeof(double) > m_in->getSize())
{
m_in->resize(m_length * sizeof(double));
m_out->resize((m_length / 2 + 1) * sizeof(fftw_complex));
}
m_forward = fftw_plan_dft_r2c_1d(m_length,
(double*)m_in->getBuffer(),
(fftw_complex*)m_out->getBuffer(),
FFTW_ESTIMATE);
m_backward = fftw_plan_dft_c2r_1d(m_length,
(fftw_complex*)m_out->getBuffer(),
(double*)m_in->getBuffer(),
FFTW_ESTIMATE);
}
float* source = (float*) buffer;
double* target = (double*) m_in->getBuffer();
float* target2 = (float*) m_buffer->getBuffer();
fftw_complex* complex = (fftw_complex*) m_out->getBuffer();
float frequency;
for(int channel = 0; channel < specs.channels; channel++)
{
for(int i = 0; i < m_length; i++)
target[i] = source[i * specs.channels + channel];
fftw_execute(m_forward);
for(int i = 0; i < m_length / 2 + 1; i++)
{
frequency = i * specs.rate / (m_length / 2.0 + 1.0);
if((frequency < m_low) || (frequency > m_high))
complex[i][0] = complex[i][1] = 0.0;
}
fftw_execute(m_backward);
for(int i = 0; i < m_length; i++)
target2[i * specs.channels + channel] = target[i] / m_length;
}
}
buffer = m_buffer->getBuffer();
}

View File

@@ -0,0 +1,99 @@
/*
* $Id$
*
* ***** BEGIN LGPL LICENSE BLOCK *****
*
* Copyright 2009 Jörg Hermann Müller
*
* This file is part of AudaSpace.
*
* AudaSpace is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AudaSpace is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with AudaSpace. If not, see <http://www.gnu.org/licenses/>.
*
* ***** END LGPL LICENSE BLOCK *****
*/
#ifndef AUD_BANDPASSREADER
#define AUD_BANDPASSREADER
#include <fftw3.h>
#include "AUD_EffectReader.h"
class AUD_Buffer;
/**
* This class only passes a specific frequency band of another reader.
*/
class AUD_BandPassReader : public AUD_EffectReader
{
private:
/**
* The playback buffer.
*/
AUD_Buffer *m_buffer;
/**
* The input buffer for fourier transformations.
*/
AUD_Buffer *m_in;
/**
* The output buffer for fourier transformations.
*/
AUD_Buffer *m_out;
/**
* The lowest passed frequency.
*/
float m_low;
/**
* The highest passed frequency.
*/
float m_high;
/**
* The fftw plan for forward transformation.
*/
fftw_plan m_forward;
/**
* The fftw plan for backward transformation.
*/
fftw_plan m_backward;
/**
* The length of the plans.
*/
int m_length;
public:
/**
* Creates a new band pass reader.
* \param reader The reader to read from.
* \param low The lowest passed frequency.
* \param high The highest passed frequency.
* \exception AUD_Exception Thrown if the reader specified is NULL.
*/
AUD_BandPassReader(AUD_IReader* reader, float low, float high);
/**
* Destroys the reader.
*/
virtual ~AUD_BandPassReader();
virtual AUD_ReaderType getType();
virtual void read(int & length, sample_t* & buffer);
};
#endif //AUD_BANDPASSREADER

View File

@@ -0,0 +1,42 @@
#
# $Id$
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): none yet.
#
# ***** END GPL LICENSE BLOCK *****
#
#
LIBNAME = aud_fftw
DIR = $(OCGDIR)/intern/audaspace
include nan_compile.mk
CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
CPPFLAGS += -I../intern
CPPFLAGS += -I../FX
CPPFLAGS += -I..
CPPFLAGS += -I.
CPPFLAGS += -I$(BF_FFTW3)/include

View File

@@ -81,7 +81,7 @@ void AUD_BufferReader::read(int & length, sample_t* & buffer)
buffer = m_buffer.get()->getBuffer()+m_position*sample_size; buffer = m_buffer.get()->getBuffer()+m_position*sample_size;
// in case the end of the buffer is reach // in case the end of the buffer is reached
if(m_buffer.get()->getSize() < (m_position+length)*sample_size) if(m_buffer.get()->getSize() < (m_position+length)*sample_size)
length = m_buffer.get()->getSize()/sample_size-m_position; length = m_buffer.get()->getSize()/sample_size-m_position;

View File

@@ -31,6 +31,7 @@
#include "AUD_LimiterFactory.h" #include "AUD_LimiterFactory.h"
#include "AUD_PingPongFactory.h" #include "AUD_PingPongFactory.h"
#include "AUD_LoopFactory.h" #include "AUD_LoopFactory.h"
#include "AUD_RectifyFactory.h"
#include "AUD_ReadDevice.h" #include "AUD_ReadDevice.h"
#include "AUD_SourceCaps.h" #include "AUD_SourceCaps.h"
#include "AUD_IReader.h" #include "AUD_IReader.h"
@@ -285,6 +286,20 @@ int AUD_stopLoop(AUD_Handle* handle)
return false; return false;
} }
AUD_Sound* AUD_rectifySound(AUD_Sound* sound)
{
assert(sound);
try
{
return new AUD_RectifyFactory(sound);
}
catch(AUD_Exception)
{
return NULL;
}
}
void AUD_unload(AUD_Sound* sound) void AUD_unload(AUD_Sound* sound)
{ {
assert(sound); assert(sound);

View File

@@ -149,6 +149,13 @@ extern AUD_Sound* AUD_loopSound(AUD_Sound* sound);
*/ */
extern int AUD_stopLoop(AUD_Handle* handle); extern int AUD_stopLoop(AUD_Handle* handle);
/**
* Rectifies a sound.
* \param sound The sound to rectify.
* \return A handle of the rectified sound.
*/
extern AUD_Sound* AUD_rectifySound(AUD_Sound* sound);
/** /**
* Unloads a sound of any type. * Unloads a sound of any type.
* \param sound The handle of the sound. * \param sound The handle of the sound.

View File

@@ -500,3 +500,43 @@ void AUD_volume_adjust_s24_be(sample_t* target, sample_t* source,
} }
} }
void AUD_rectify_u8(sample_t* target, sample_t* source, int count)
{
for(int i=0; i<count; i++)
target[i] = source[i] < 0x80 ? 0x0100 - source[i] : source[i];
}
void AUD_rectify_s24_le(sample_t* target, sample_t* source, int count)
{
count *= 3;
int value;
for(int i=0; i<count; i+=3)
{
value = source[i+2] << 16 | source[i+1] << 8 | source[i];
value |= (((value & 0x800000) >> 23) * 255) << 24;
if(value < 0)
value = -value;
target[i+2] = value >> 16;
target[i+1] = value >> 8;
target[i] = value;
}
}
void AUD_rectify_s24_be(sample_t* target, sample_t* source, int count)
{
count *= 3;
int value;
for(int i=0; i < count; i+=3)
{
value = source[i] << 16 | source[i+1] << 8 | source[i+2];
value |= (((value & 0x800000) >> 23) * 255) << 24;
if(value < 0)
value = -value;
target[i] = value >> 16;
target[i+1] = value >> 8;
target[i+2] = value;
}
}

View File

@@ -46,6 +46,8 @@ typedef void (*AUD_convert_f)(sample_t* target, sample_t* source, int length);
typedef void (*AUD_volume_adjust_f)(sample_t* target, sample_t* source, typedef void (*AUD_volume_adjust_f)(sample_t* target, sample_t* source,
int count, float volume); int count, float volume);
typedef void (*AUD_rectify_f)(sample_t* target, sample_t* source, int count);
template <class T> template <class T>
void AUD_convert_copy(sample_t* target, sample_t* source, int length) void AUD_convert_copy(sample_t* target, sample_t* source, int length)
{ {
@@ -153,4 +155,19 @@ void AUD_volume_adjust_s24_le(sample_t* target, sample_t* source,
void AUD_volume_adjust_s24_be(sample_t* target, sample_t* source, void AUD_volume_adjust_s24_be(sample_t* target, sample_t* source,
int count, float volume); int count, float volume);
template <class T>
void AUD_rectify(sample_t* target, sample_t* source, int count)
{
T* t = (T*)target;
T* s = (T*)source;
for(int i=0; i < count; i++)
t[i] = s[i] < 0 ? -s[i] : s[i];
}
void AUD_rectify_u8(sample_t* target, sample_t* source, int count);
void AUD_rectify_s24_le(sample_t* target, sample_t* source, int count);
void AUD_rectify_s24_be(sample_t* target, sample_t* source, int count);
#endif //AUD_CONVERTERFUNCTIONS #endif //AUD_CONVERTERFUNCTIONS

View File

@@ -59,9 +59,10 @@ endif
ifeq ($(WITH_SNDFILE),true) ifeq ($(WITH_SNDFILE),true)
CPPFLAGS += -DWITH_SNDFILE CPPFLAGS += -DWITH_SNDFILE
CPPFLAGS += -I../sndfile CPPFLAGS += -I../sndfile
CPPFLAGS += -I$(NAN_SNDFILE)/include
endif endif
CPPFLAGS += -I$(LCGDIR)/samplerate/include/ CPPFLAGS += -I$(NAN_SAMPLERATE)/include/
CPPFLAGS += -I../ffmpeg CPPFLAGS += -I../ffmpeg
CPPFLAGS += -I../FX CPPFLAGS += -I../FX
CPPFLAGS += -I../SDL CPPFLAGS += -I../SDL

View File

@@ -44,7 +44,7 @@
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="2" Optimization="2"
InlineFunctionExpansion="2" InlineFunctionExpansion="2"
AdditionalIncludeDirectories="..\..;..\..\ffmpeg;..\..\FX;..\..\intern;..\..\OpenAL;..\..\SDL;..\..\SRC;..\..\sndfile;..\..\..\..\..\lib\windows\pthreads\include;..\..\..\..\..\lib\windows\samplerate\include;..\..\..\..\..\lib\windows\ffmpeg\include;..\..\..\..\..\lib\windows\ffmpeg\include\msvc;..\..\..\..\..\lib\windows\sdl\include;..\..\..\..\..\lib\windows\openal\include;..\..\..\..\..\lib\windows\jack\include;..\..\..\..\..\lib\windows\sndfile\include" AdditionalIncludeDirectories="..\..;..\..\ffmpeg;..\..\FX;..\..\intern;..\..\OpenAL;..\..\SDL;..\..\SRC;..\..\sndfile;..\..\..\..\..\lib\windows\pthreads\include;..\..\..\..\..\lib\windows\samplerate\include;..\..\..\..\..\lib\windows\ffmpeg\include;..\..\..\..\..\lib\windows\ffmpeg\include\msvc;..\..\..\..\..\lib\windows\sdl\include;..\..\..\..\..\lib\windows\openal\include;..\..\..\..\..\lib\windows\jack\include;..\..\..\..\..\lib\windows\sndfile\include;..\..\..\..\..\lib\windows\fftw3\include"
PreprocessorDefinitions="WIN32,NDEBUG,_LIB,WITH_FFMPEG,WITH_SDL,WITH_OPENAL" PreprocessorDefinitions="WIN32,NDEBUG,_LIB,WITH_FFMPEG,WITH_SDL,WITH_OPENAL"
StringPooling="true" StringPooling="true"
RuntimeLibrary="0" RuntimeLibrary="0"
@@ -118,7 +118,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="..\..;..\..\ffmpeg;..\..\FX;..\..\intern;..\..\OpenAL;..\..\SDL;..\..\SRC;..\..\sndfile;..\..\..\..\..\lib\windows\pthreads\include;..\..\..\..\..\lib\windows\samplerate\include;..\..\..\..\..\lib\windows\ffmpeg\include;..\..\..\..\..\lib\windows\ffmpeg\include\msvc;..\..\..\..\..\lib\windows\sdl\include;..\..\..\..\..\lib\windows\openal\include;..\..\..\..\..\lib\windows\jack\include;..\..\..\..\..\lib\windows\sndfile\include" AdditionalIncludeDirectories="..\..;..\..\ffmpeg;..\..\FX;..\..\intern;..\..\OpenAL;..\..\SDL;..\..\SRC;..\..\sndfile;..\..\..\..\..\lib\windows\pthreads\include;..\..\..\..\..\lib\windows\samplerate\include;..\..\..\..\..\lib\windows\ffmpeg\include;..\..\..\..\..\lib\windows\ffmpeg\include\msvc;..\..\..\..\..\lib\windows\sdl\include;..\..\..\..\..\lib\windows\openal\include;..\..\..\..\..\lib\windows\jack\include;..\..\..\..\..\lib\windows\sndfile\include;..\..\..\..\..\lib\windows\fftw3\include"
PreprocessorDefinitions="WIN32,_DEBUG,_LIB,WITH_FFMPEG,WITH_SDL,WITH_OPENAL" PreprocessorDefinitions="WIN32,_DEBUG,_LIB,WITH_FFMPEG,WITH_SDL,WITH_OPENAL"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
RuntimeLibrary="1" RuntimeLibrary="1"
@@ -193,7 +193,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
InlineFunctionExpansion="2" InlineFunctionExpansion="2"
AdditionalIncludeDirectories="..\..;..\..\ffmpeg;..\..\FX;..\..\intern;..\..\OpenAL;..\..\SDL;..\..\SRC;..\..\sndfile;..\..\..\..\..\lib\windows\pthreads\include;..\..\..\..\..\lib\windows\samplerate\include;..\..\..\..\..\lib\windows\ffmpeg\include;..\..\..\..\..\lib\windows\ffmpeg\include\msvc;..\..\..\..\..\lib\windows\sdl\include;..\..\..\..\..\lib\windows\openal\include;..\..\..\..\..\lib\windows\jack\include;..\..\..\..\..\lib\windows\sndfile\include" AdditionalIncludeDirectories="..\..;..\..\ffmpeg;..\..\FX;..\..\intern;..\..\OpenAL;..\..\SDL;..\..\SRC;..\..\sndfile;..\..\..\..\..\lib\windows\pthreads\include;..\..\..\..\..\lib\windows\samplerate\include;..\..\..\..\..\lib\windows\ffmpeg\include;..\..\..\..\..\lib\windows\ffmpeg\include\msvc;..\..\..\..\..\lib\windows\sdl\include;..\..\..\..\..\lib\windows\openal\include;..\..\..\..\..\lib\windows\jack\include;..\..\..\..\..\lib\windows\sndfile\include;..\..\..\..\..\lib\windows\fftw3\include"
PreprocessorDefinitions="WIN32,NDEBUG,_LIB,WITH_FFMPEG,WITH_SDL,WITH_OPENAL" PreprocessorDefinitions="WIN32,NDEBUG,_LIB,WITH_FFMPEG,WITH_SDL,WITH_OPENAL"
StringPooling="true" StringPooling="true"
RuntimeLibrary="2" RuntimeLibrary="2"
@@ -267,7 +267,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="..\..;..\..\ffmpeg;..\..\FX;..\..\intern;..\..\OpenAL;..\..\SDL;..\..\SRC;..\..\sndfile;..\..\..\..\..\lib\windows\pthreads\include;..\..\..\..\..\lib\windows\samplerate\include;..\..\..\..\..\lib\windows\ffmpeg\include;..\..\..\..\..\lib\windows\ffmpeg\include\msvc;..\..\..\..\..\lib\windows\sdl\include;..\..\..\..\..\lib\windows\openal\include;..\..\..\..\..\lib\windows\jack\include;..\..\..\..\..\lib\windows\sndfile\include" AdditionalIncludeDirectories="..\..;..\..\ffmpeg;..\..\FX;..\..\intern;..\..\OpenAL;..\..\SDL;..\..\SRC;..\..\sndfile;..\..\..\..\..\lib\windows\pthreads\include;..\..\..\..\..\lib\windows\samplerate\include;..\..\..\..\..\lib\windows\ffmpeg\include;..\..\..\..\..\lib\windows\ffmpeg\include\msvc;..\..\..\..\..\lib\windows\sdl\include;..\..\..\..\..\lib\windows\openal\include;..\..\..\..\..\lib\windows\jack\include;..\..\..\..\..\lib\windows\sndfile\include;..\..\..\..\..\lib\windows\fftw3\include"
PreprocessorDefinitions="WIN32,_DEBUG,_LIB,WITH_FFMPEG,WITH_SDL,WITH_OPENAL" PreprocessorDefinitions="WIN32,_DEBUG,_LIB,WITH_FFMPEG,WITH_SDL,WITH_OPENAL"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
RuntimeLibrary="3" RuntimeLibrary="3"
@@ -629,6 +629,22 @@
RelativePath="..\..\FX\AUD_PitchReader.h" RelativePath="..\..\FX\AUD_PitchReader.h"
> >
</File> </File>
<File
RelativePath="..\..\FX\AUD_RectifyFactory.cpp"
>
</File>
<File
RelativePath="..\..\FX\AUD_RectifyFactory.h"
>
</File>
<File
RelativePath="..\..\FX\AUD_RectifyReader.cpp"
>
</File>
<File
RelativePath="..\..\FX\AUD_RectifyReader.h"
>
</File>
<File <File
RelativePath="..\..\FX\AUD_ReverseFactory.cpp" RelativePath="..\..\FX\AUD_ReverseFactory.cpp"
> >
@@ -762,6 +778,26 @@
> >
</File> </File>
</Filter> </Filter>
<Filter
Name="fftw"
>
<File
RelativePath="..\..\fftw\AUD_BandPassFactory.cpp"
>
</File>
<File
RelativePath="..\..\fftw\AUD_BandPassFactory.h"
>
</File>
<File
RelativePath="..\..\fftw\AUD_BandPassReader.cpp"
>
</File>
<File
RelativePath="..\..\fftw\AUD_BandPassReader.h"
>
</File>
</Filter>
</Files> </Files>
<Globals> <Globals>
</Globals> </Globals>

View File

@@ -35,6 +35,7 @@ include nan_compile.mk
CCFLAGS += $(LEVEL_1_CPP_WARNINGS) CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
CPPFLAGS += -I$(NAN_SNDFILE)/include
CPPFLAGS += -I../intern CPPFLAGS += -I../intern
CPPFLAGS += -I.. CPPFLAGS += -I..
CPPFLAGS += -I. CPPFLAGS += -I.

View File

@@ -283,8 +283,12 @@ sgstrf (superlu_options_t *options, SuperMatrix *A,
* -------------------------------------- */ * -------------------------------------- */
/* Determine the union of the row structure of the snode */ /* Determine the union of the row structure of the snode */
if ( (*info = ssnode_dfs(jcol, kcol, asub, xa_begin, xa_end, if ( (*info = ssnode_dfs(jcol, kcol, asub, xa_begin, xa_end,
xprune, marker, &Glu)) != 0 ) xprune, marker, &Glu)) != 0 ) {
if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r);
SUPERLU_FREE (iperm_c);
SUPERLU_FREE (relax_end);
return; return;
}
nextu = xusub[jcol]; nextu = xusub[jcol];
nextlu = xlusup[jcol]; nextlu = xlusup[jcol];
@@ -293,8 +297,12 @@ sgstrf (superlu_options_t *options, SuperMatrix *A,
new_next = nextlu + (xlsub[fsupc+1]-xlsub[fsupc])*(kcol-jcol+1); new_next = nextlu + (xlsub[fsupc+1]-xlsub[fsupc])*(kcol-jcol+1);
nzlumax = Glu.nzlumax; nzlumax = Glu.nzlumax;
while ( new_next > nzlumax ) { while ( new_next > nzlumax ) {
if ( (*info = sLUMemXpand(jcol, nextlu, LUSUP, &nzlumax, &Glu)) ) if ( (*info = sLUMemXpand(jcol, nextlu, LUSUP, &nzlumax, &Glu)) ) {
return; if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r);
SUPERLU_FREE (iperm_c);
SUPERLU_FREE (relax_end);
return;
}
} }
for (icol = jcol; icol<= kcol; icol++) { for (icol = jcol; icol<= kcol; icol++) {
@@ -350,17 +358,31 @@ sgstrf (superlu_options_t *options, SuperMatrix *A,
if ((*info = scolumn_dfs(m, jj, perm_r, &nseg, &panel_lsub[k], if ((*info = scolumn_dfs(m, jj, perm_r, &nseg, &panel_lsub[k],
segrep, &repfnz[k], xprune, marker, segrep, &repfnz[k], xprune, marker,
parent, xplore, &Glu)) != 0) return; parent, xplore, &Glu)) != 0) {
if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r);
SUPERLU_FREE (iperm_c);
SUPERLU_FREE (relax_end);
return;
}
/* Numeric updates */ /* Numeric updates */
if ((*info = scolumn_bmod(jj, (nseg - nseg1), &dense[k], if ((*info = scolumn_bmod(jj, (nseg - nseg1), &dense[k],
tempv, &segrep[nseg1], &repfnz[k], tempv, &segrep[nseg1], &repfnz[k],
jcol, &Glu, stat)) != 0) return; jcol, &Glu, stat)) != 0) {
if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r);
SUPERLU_FREE (iperm_c);
SUPERLU_FREE (relax_end);
return;
}
/* Copy the U-segments to ucol[*] */ /* Copy the U-segments to ucol[*] */
if ((*info = scopy_to_ucol(jj, nseg, segrep, &repfnz[k], if ((*info = scopy_to_ucol(jj, nseg, segrep, &repfnz[k],
perm_r, &dense[k], &Glu)) != 0) perm_r, &dense[k], &Glu)) != 0) {
return; if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r);
SUPERLU_FREE (iperm_c);
SUPERLU_FREE (relax_end);
return;
}
if ( (*info = spivotL(jj, diag_pivot_thresh, &usepr, perm_r, if ( (*info = spivotL(jj, diag_pivot_thresh, &usepr, perm_r,
iperm_r, iperm_c, &pivrow, &Glu, stat)) ) iperm_r, iperm_c, &pivrow, &Glu, stat)) )
@@ -429,5 +451,4 @@ sgstrf (superlu_options_t *options, SuperMatrix *A,
if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r); if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r);
SUPERLU_FREE (iperm_c); SUPERLU_FREE (iperm_c);
SUPERLU_FREE (relax_end); SUPERLU_FREE (relax_end);
} }

View File

@@ -415,6 +415,10 @@
RelativePath="..\..\..\source\blender\editors\interface\interface_layout.c" RelativePath="..\..\..\source\blender\editors\interface\interface_layout.c"
> >
</File> </File>
<File
RelativePath="..\..\..\source\blender\editors\interface\interface_ops.c"
>
</File>
<File <File
RelativePath="..\..\..\source\blender\editors\interface\interface_panel.c" RelativePath="..\..\..\source\blender\editors\interface\interface_panel.c"
> >

View File

@@ -1126,23 +1126,21 @@ class Export3DS(bpy.types.Operator):
def execute(self, context): def execute(self, context):
save_3ds(self.properties.path, context) save_3ds(self.properties.path, context)
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.manager wm = context.manager
wm.add_fileselect(self) wm.add_fileselect(self)
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
def poll(self, context): # Poll isnt working yet def poll(self, context): # Poll isnt working yet
return context.active_object != None return context.active_object != None
bpy.ops.add(Export3DS) bpy.types.register(Export3DS)
# Add to a menu # Add to a menu
import dynamic_menu
def menu_func(self, context): def menu_func(self, context):
default_path = bpy.data.filename.replace(".blend", ".3ds") default_path = bpy.data.filename.replace(".blend", ".3ds")
self.layout.operator(Export3DS.bl_idname, text="Autodesk 3DS...").path = default_path self.layout.operator(Export3DS.bl_idname, text="Autodesk 3DS...").path = default_path
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func) bpy.types.INFO_MT_file_export.append(menu_func)

View File

@@ -651,8 +651,8 @@ def write(filename, batch_objects = None, \
}''' % (curtime)) }''' % (curtime))
file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime) file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime)
file.write('\nCreator: "Blender3D version 2.5"') file.write('\nCreator: "Blender3D version %s"' % bpy.version_string)
# file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version'))
pose_items = [] # list of (fbxName, matrix) to write pose data for, easier to collect allong the way pose_items = [] # list of (fbxName, matrix) to write pose data for, easier to collect allong the way
@@ -3361,7 +3361,7 @@ class ExportFBX(bpy.types.Operator):
# to the class instance from the operator settings before calling. # to the class instance from the operator settings before calling.
path = StringProperty(name="File Path", description="File path used for exporting the FBX file", maxlen= 1024, default= "") path = StringProperty(name="File Path", description="File path used for exporting the FBX file", maxlen= 1024, default="")
EXP_OBS_SELECTED = BoolProperty(name="Selected Objects", description="Export selected objects on visible layers", default=True) EXP_OBS_SELECTED = BoolProperty(name="Selected Objects", description="Export selected objects on visible layers", default=True)
# EXP_OBS_SCENE = BoolProperty(name="Scene Objects", description="Export all objects in this scene", default=True) # EXP_OBS_SCENE = BoolProperty(name="Scene Objects", description="Export all objects in this scene", default=True)
@@ -3387,7 +3387,7 @@ class ExportFBX(bpy.types.Operator):
BATCH_ENABLE = BoolProperty(name="Enable Batch", description="Automate exporting multiple scenes or groups to files", default=False) BATCH_ENABLE = BoolProperty(name="Enable Batch", description="Automate exporting multiple scenes or groups to files", default=False)
BATCH_GROUP = BoolProperty(name="Group > File", description="Export each group as an FBX file, if false, export each scene as an FBX file", default=False) BATCH_GROUP = BoolProperty(name="Group > File", description="Export each group as an FBX file, if false, export each scene as an FBX file", default=False)
BATCH_OWN_DIR = BoolProperty(name="Own Dir", description="Create a dir for each exported file", default=True) BATCH_OWN_DIR = BoolProperty(name="Own Dir", description="Create a dir for each exported file", default=True)
BATCH_FILE_PREFIX = StringProperty(name="Prefix", description="Prefix each file with this name", maxlen= 1024, default="") BATCH_FILE_PREFIX = StringProperty(name="Prefix", description="Prefix each file with this name", maxlen=1024, default="")
def poll(self, context): def poll(self, context):
@@ -3426,15 +3426,15 @@ class ExportFBX(bpy.types.Operator):
self.properties.BATCH_FILE_PREFIX, self.properties.BATCH_FILE_PREFIX,
self.properties.BATCH_OWN_DIR) self.properties.BATCH_OWN_DIR)
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.manager wm = context.manager
wm.add_fileselect(self) wm.add_fileselect(self)
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
bpy.ops.add(ExportFBX) bpy.types.register(ExportFBX)
# if __name__ == "__main__": # if __name__ == "__main__":
# bpy.ops.EXPORT_OT_ply(filename="/tmp/test.ply") # bpy.ops.EXPORT_OT_ply(filename="/tmp/test.ply")
@@ -3462,13 +3462,8 @@ bpy.ops.add(ExportFBX)
# SMALL or COSMETICAL # SMALL or COSMETICAL
# - find a way to get blender version, and put it in bpy.util?, old was Blender.Get('version') # - find a way to get blender version, and put it in bpy.util?, old was Blender.Get('version')
# Add to a menu
import dynamic_menu
def menu_func(self, context): def menu_func(self, context):
default_path = bpy.data.filename.replace(".blend", ".fbx") default_path = bpy.data.filename.replace(".blend", ".fbx")
self.layout.operator(ExportFBX.bl_idname, text="Autodesk FBX...").path = default_path self.layout.operator(ExportFBX.bl_idname, text="Autodesk FBX...").path = default_path
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func) menu_item = bpy.types.INFO_MT_file_export.append(menu_func)

View File

@@ -96,7 +96,7 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
numverts = len(me.verts) numverts = len(me.verts)
numframes = PREF_ENDFRAME-PREF_STARTFRAME + 1 numframes = PREF_ENDFRAME - PREF_STARTFRAME + 1
PREF_FPS = float(PREF_FPS) PREF_FPS = float(PREF_FPS)
f = open(filename, 'wb') #no Errors yet:Safe to create file f = open(filename, 'wb') #no Errors yet:Safe to create file
@@ -104,7 +104,7 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
f.write(pack(">2i", numframes, numverts)) f.write(pack(">2i", numframes, numverts))
# Write the frame times (should we use the time IPO??) # Write the frame times (should we use the time IPO??)
f.write( pack(">%df" % (numframes), *[frame / PREF_FPS for frame in range(numframes)]) ) # seconds f.write(pack(">%df" % (numframes), *[frame / PREF_FPS for frame in range(numframes)])) # seconds
#rest frame needed to keep frames in sync #rest frame needed to keep frames in sync
""" """
@@ -159,8 +159,8 @@ class ExportMDD(bpy.types.Operator):
# List of operator properties, the attributes will be assigned # List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling. # to the class instance from the operator settings before calling.
path = StringProperty(name="File Path", description="File path used for exporting the MDD file", maxlen= 1024, default= "") path = StringProperty(name="File Path", description="File path used for exporting the MDD file", maxlen=1024)
fps = IntProperty(name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default= 25) fps = IntProperty(name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default=25)
start_frame = IntProperty(name="Start Frame", description="Start frame for baking", min=minframe, max=maxframe, default=1) start_frame = IntProperty(name="Start Frame", description="Start frame for baking", min=minframe, max=maxframe, default=1)
end_frame = IntProperty(name="End Frame", description="End frame for baking", min=minframe, max=maxframe, default=250) end_frame = IntProperty(name="End Frame", description="End frame for baking", min=minframe, max=maxframe, default=250)
@@ -173,24 +173,21 @@ class ExportMDD(bpy.types.Operator):
raise Exception("filename not set") raise Exception("filename not set")
write(self.properties.path, context.scene, context.active_object, write(self.properties.path, context.scene, context.active_object,
self.properties.start_frame, self.properties.end_frame, self.properties.fps) self.properties.start_frame, self.properties.end_frame, self.properties.fps)
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.manager wm = context.manager
wm.add_fileselect(self) wm.add_fileselect(self)
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
bpy.ops.add(ExportMDD) bpy.types.register(ExportMDD)
# Add to a menu
import dynamic_menu
def menu_func(self, context): def menu_func(self, context):
default_path = bpy.data.filename.replace(".blend", ".mdd") default_path = bpy.data.filename.replace(".blend", ".mdd")
self.layout.operator(ExportMDD.bl_idname, text="Vertex Keyframe Animation (.mdd)...").path = default_path self.layout.operator(ExportMDD.bl_idname, text="Vertex Keyframe Animation (.mdd)...").path = default_path
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func) bpy.types.INFO_MT_file_export.append(menu_func)
if __name__ == '__main__': if __name__ == '__main__':
bpy.ops.export.mdd(path="/tmp/test.mdd") bpy.ops.export.mdd(path="/tmp/test.mdd")

View File

@@ -40,29 +40,6 @@ All objects that can be represented as a mesh (mesh, curve, metaball, surface, t
will be exported as mesh data. will be exported as mesh data.
""" """
# --------------------------------------------------------------------------
# OBJ Export v1.1 by Campbell Barton (AKA Ideasman)
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
# import math and other in functions that use them for the sake of fast Blender startup # import math and other in functions that use them for the sake of fast Blender startup
# import math # import math
import os import os
@@ -384,8 +361,7 @@ def write(filename, objects, scene,
file = open(filename, "w") file = open(filename, "w")
# Write Header # Write Header
version = "2.5" file.write('# Blender3D v%s OBJ File: %s\n' % (bpy.version_string, bpy.data.filename.split('/')[-1].split('\\')[-1] ))
file.write('# Blender3D v%s OBJ File: %s\n' % (version, bpy.data.filename.split('/')[-1].split('\\')[-1] ))
file.write('# www.blender3d.org\n') file.write('# www.blender3d.org\n')
# Tell the obj file what material file to use. # Tell the obj file what material file to use.
@@ -444,7 +420,7 @@ def write(filename, objects, scene,
me = ob.create_mesh(EXPORT_APPLY_MODIFIERS, 'PREVIEW') me = ob.create_mesh(EXPORT_APPLY_MODIFIERS, 'PREVIEW')
if EXPORT_ROTX90: if EXPORT_ROTX90:
me.transform(ob_mat * mat_xrot90) me.transform(mat_xrot90 * ob_mat)
else: else:
me.transform(ob_mat) me.transform(ob_mat)
@@ -980,26 +956,20 @@ class ExportOBJ(bpy.types.Operator):
EXPORT_SEL_ONLY=self.properties.use_selection, EXPORT_SEL_ONLY=self.properties.use_selection,
EXPORT_ALL_SCENES=self.properties.use_all_scenes) EXPORT_ALL_SCENES=self.properties.use_all_scenes)
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.manager wm = context.manager
wm.add_fileselect(self) wm.add_fileselect(self)
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
bpy.types.register(ExportOBJ)
bpy.ops.add(ExportOBJ)
import dynamic_menu
def menu_func(self, context): def menu_func(self, context):
default_path = bpy.data.filename.replace(".blend", ".obj") default_path = bpy.data.filename.replace(".blend", ".obj")
self.layout.operator(ExportOBJ.bl_idname, text="Wavefront (.obj)...").path = default_path self.layout.operator(ExportOBJ.bl_idname, text="Wavefront (.obj)...").path = default_path
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func) menu_item = bpy.types.INFO_MT_file_export.append(menu_func)
if __name__ == "__main__": if __name__ == "__main__":
bpy.ops.EXPORT_OT_obj(filename="/tmp/test.obj") bpy.ops.EXPORT_OT_obj(filename="/tmp/test.obj")

View File

@@ -180,7 +180,7 @@ def write(filename, scene, ob, \
normal_key = rvec3d(normal) normal_key = rvec3d(normal)
if faceUV: if faceUV:
uvcoord = uv[j][0], 1.0-uv[j][1] uvcoord = uv[j][0], 1.0 - uv[j][1]
uvcoord_key = rvec2d(uvcoord) uvcoord_key = rvec2d(uvcoord)
elif vertexUV: elif vertexUV:
uvcoord = v.uvco[0], 1.0 - v.uvco[1] uvcoord = v.uvco[0], 1.0 - v.uvco[1]
@@ -205,8 +205,7 @@ def write(filename, scene, ob, \
file.write('ply\n') file.write('ply\n')
file.write('format ascii 1.0\n') file.write('format ascii 1.0\n')
version = "2.5" # Blender.Get('version') file.write('comment Created by Blender3D %s - www.blender.org, source file: %s\n' % (bpy.version_string, bpy.data.filename.split('/')[-1].split('\\')[-1]))
file.write('comment Created by Blender3D %s - www.blender.org, source file: %s\n' % (version, bpy.data.filename.split('/')[-1].split('\\')[-1]))
file.write('element vertex %d\n' % len(ply_verts)) file.write('element vertex %d\n' % len(ply_verts))
@@ -246,7 +245,7 @@ def write(filename, scene, ob, \
file.write('\n') file.write('\n')
for pf in ply_faces: for pf in ply_faces:
if len(pf)==3: if len(pf) == 3:
file.write('3 %d %d %d\n' % tuple(pf)) file.write('3 %d %d %d\n' % tuple(pf))
else: else:
file.write('4 %d %d %d %d\n' % tuple(pf)) file.write('4 %d %d %d %d\n' % tuple(pf))
@@ -297,12 +296,12 @@ class ExportPLY(bpy.types.Operator):
EXPORT_COLORS=self.properties.use_colors, EXPORT_COLORS=self.properties.use_colors,
) )
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.manager wm = context.manager
wm.add_fileselect(self) wm.add_fileselect(self)
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
@@ -316,16 +315,15 @@ class ExportPLY(bpy.types.Operator):
row.prop(props, "use_colors") row.prop(props, "use_colors")
bpy.ops.add(ExportPLY) bpy.types.register(ExportPLY)
import dynamic_menu
def menu_func(self, context): def menu_func(self, context):
default_path = bpy.data.filename.replace(".blend", ".ply") default_path = bpy.data.filename.replace(".blend", ".ply")
self.layout.operator(ExportPLY.bl_idname, text="Stanford (.ply)...").path = default_path self.layout.operator(ExportPLY.bl_idname, text="Stanford (.ply)...").path = default_path
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func) bpy.types.INFO_MT_file_export.append(menu_func)
if __name__ == "__main__": if __name__ == "__main__":
bpy.ops.export.ply(path="/tmp/test.ply") bpy.ops.export.ply(path="/tmp/test.ply")

View File

@@ -1233,22 +1233,21 @@ class ExportX3D(bpy.types.Operator):
def execute(self, context): def execute(self, context):
x3d_export(self.properties.path, context, self.properties.apply_modifiers, self.properties.triangulate, self.properties.compress) x3d_export(self.properties.path, context, self.properties.apply_modifiers, self.properties.triangulate, self.properties.compress)
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.manager wm = context.manager
wm.add_fileselect(self) wm.add_fileselect(self)
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
bpy.ops.add(ExportX3D) bpy.types.register(ExportX3D)
import dynamic_menu
def menu_func(self, context): def menu_func(self, context):
default_path = bpy.data.filename.replace(".blend", ".x3d") default_path = bpy.data.filename.replace(".blend", ".x3d")
self.layout.operator(ExportX3D.bl_idname, text="X3D Extensible 3D (.x3d)...").path = default_path self.layout.operator(ExportX3D.bl_idname, text="X3D Extensible 3D (.x3d)...").path = default_path
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func) bpy.types.INFO_MT_file_export.append(menu_func)
# NOTES # NOTES
# - blender version is hardcoded # - blender version is hardcoded

View File

@@ -887,17 +887,15 @@ class BvhImporter(bpy.types.Operator):
read_bvh(context, self.properties.path) read_bvh(context, self.properties.path)
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.manager wm = context.manager
wm.add_fileselect(self) wm.add_fileselect(self)
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
bpy.ops.add(BvhImporter) bpy.types.register(BvhImporter)
import dynamic_menu
menu_func = lambda self, context: self.layout.operator(BvhImporter.bl_idname, text="Motion Capture (.bvh)...") menu_func = lambda self, context: self.layout.operator(BvhImporter.bl_idname, text="Motion Capture (.bvh)...")
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_import, menu_func) bpy.types.INFO_MT_file_import.append(menu_func)

View File

@@ -1151,7 +1151,7 @@ class IMPORT_OT_autodesk_3ds(bpy.types.Operator):
# List of operator properties, the attributes will be assigned # List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling. # to the class instance from the operator settings before calling.
path = StringProperty(name="File Path", description="File path used for importing the 3DS file", maxlen= 1024, default= ""), path = StringProperty(name="File Path", description="File path used for importing the 3DS file", maxlen= 1024, default= "")
# size_constraint = FloatProperty(name="Size Constraint", description="Scale the model by 10 until it reacehs the size constraint. Zero Disables.", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=10.0), # size_constraint = FloatProperty(name="Size Constraint", description="Scale the model by 10 until it reacehs the size constraint. Zero Disables.", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=10.0),
# search_images = BoolProperty(name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True), # search_images = BoolProperty(name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True),
@@ -1159,19 +1159,18 @@ class IMPORT_OT_autodesk_3ds(bpy.types.Operator):
def execute(self, context): def execute(self, context):
load_3ds(self.properties.path, context, 0.0, False, False) load_3ds(self.properties.path, context, 0.0, False, False)
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.manager wm = context.manager
wm.add_fileselect(self) wm.add_fileselect(self)
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
bpy.ops.add(IMPORT_OT_autodesk_3ds) bpy.types.register(IMPORT_OT_autodesk_3ds)
import dynamic_menu
menu_func = lambda self, context: self.layout.operator(IMPORT_OT_autodesk_3ds.bl_idname, text="3D Studio (.3ds)...") menu_func = lambda self, context: self.layout.operator(IMPORT_OT_autodesk_3ds.bl_idname, text="3D Studio (.3ds)...")
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_import, menu_func) bpy.types.INFO_MT_file_import.append(menu_func)
# NOTES: # NOTES:
# why add 1 extra vertex? and remove it when done? # why add 1 extra vertex? and remove it when done? - "Answer - eekadoodle - would need to re-order UV's without this since face order isnt always what we give blender, BMesh will solve :D"
# disabled scaling to size, this requires exposing bb (easy) and understanding how it works (needs some time) # disabled scaling to size, this requires exposing bb (easy) and understanding how it works (needs some time)

View File

@@ -1616,20 +1616,19 @@ class IMPORT_OT_obj(bpy.types.Operator):
self.properties.IMAGE_SEARCH, self.properties.IMAGE_SEARCH,
self.properties.POLYGROUPS) self.properties.POLYGROUPS)
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.manager wm = context.manager
wm.add_fileselect(self) wm.add_fileselect(self)
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
bpy.ops.add(IMPORT_OT_obj) bpy.types.register(IMPORT_OT_obj)
import dynamic_menu
menu_func = lambda self, context: self.layout.operator(IMPORT_OT_obj.bl_idname, text="Wavefront (.obj)...") menu_func = lambda self, context: self.layout.operator(IMPORT_OT_obj.bl_idname, text="Wavefront (.obj)...")
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_import, menu_func) menu_item = bpy.types.INFO_MT_file_import.append(menu_func)
# NOTES (all line numbers refer to 2.4x import_obj.py, not this file) # NOTES (all line numbers refer to 2.4x import_obj.py, not this file)

View File

@@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, # along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

View File

@@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, # along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@@ -22,129 +22,129 @@ from netrender.utils import *
import netrender.model import netrender.model
class RatingRule: class RatingRule:
def rate(self, job): def rate(self, job):
return 0 return 0
class ExclusionRule: class ExclusionRule:
def test(self, job): def test(self, job):
return False return False
class PriorityRule: class PriorityRule:
def test(self, job): def test(self, job):
return False return False
class Balancer: class Balancer:
def __init__(self): def __init__(self):
self.rules = [] self.rules = []
self.priorities = [] self.priorities = []
self.exceptions = [] self.exceptions = []
def addRule(self, rule): def addRule(self, rule):
self.rules.append(rule) self.rules.append(rule)
def addPriority(self, priority): def addPriority(self, priority):
self.priorities.append(priority) self.priorities.append(priority)
def addException(self, exception): def addException(self, exception):
self.exceptions.append(exception) self.exceptions.append(exception)
def applyRules(self, job): def applyRules(self, job):
return sum((rule.rate(job) for rule in self.rules)) return sum((rule.rate(job) for rule in self.rules))
def applyPriorities(self, job): def applyPriorities(self, job):
for priority in self.priorities: for priority in self.priorities:
if priority.test(job): if priority.test(job):
return True # priorities are first return True # priorities are first
return False return False
def applyExceptions(self, job): def applyExceptions(self, job):
for exception in self.exceptions: for exception in self.exceptions:
if exception.test(job): if exception.test(job):
return True # exceptions are last return True # exceptions are last
return False return False
def sortKey(self, job): def sortKey(self, job):
return (1 if self.applyExceptions(job) else 0, # exceptions after return (1 if self.applyExceptions(job) else 0, # exceptions after
0 if self.applyPriorities(job) else 1, # priorities first 0 if self.applyPriorities(job) else 1, # priorities first
self.applyRules(job)) self.applyRules(job))
def balance(self, jobs): def balance(self, jobs):
if jobs: if jobs:
# use inline copy to make sure the list is still accessible while sorting # use inline copy to make sure the list is still accessible while sorting
jobs[:] = sorted(jobs, key=self.sortKey) jobs[:] = sorted(jobs, key=self.sortKey)
return jobs[0] return jobs[0]
else: else:
return None return None
# ========================== # ==========================
class RatingUsage(RatingRule): class RatingUsage(RatingRule):
def __str__(self): def __str__(self):
return "Usage rating" return "Usage rating"
def rate(self, job): def rate(self, job):
# less usage is better # less usage is better
return job.usage / job.priority return job.usage / job.priority
class RatingUsageByCategory(RatingRule): class RatingUsageByCategory(RatingRule):
def __str__(self): def __str__(self):
return "Usage per category rating" return "Usage per category rating"
def __init__(self, get_jobs):
self.getJobs = get_jobs
def rate(self, job):
total_category_usage = sum([j.usage for j in self.getJobs() if j.category == job.category])
maximum_priority = max([j.priority for j in self.getJobs() if j.category == job.category])
# less usage is better
return total_category_usage / maximum_priority
class NewJobPriority(PriorityRule):
def str_limit(self):
return "less than %i frame%s done" % (self.limit, "s" if self.limit > 1 else "")
def __str__(self): def __init__(self, get_jobs):
return "Priority to new jobs" self.getJobs = get_jobs
def rate(self, job):
def __init__(self, limit = 1): total_category_usage = sum([j.usage for j in self.getJobs() if j.category == job.category])
self.limit = limit maximum_priority = max([j.priority for j in self.getJobs() if j.category == job.category])
def test(self, job): # less usage is better
return job.countFrames(status = DONE) < self.limit return total_category_usage / maximum_priority
class NewJobPriority(PriorityRule):
def str_limit(self):
return "less than %i frame%s done" % (self.limit, "s" if self.limit > 1 else "")
def __str__(self):
return "Priority to new jobs"
def __init__(self, limit = 1):
self.limit = limit
def test(self, job):
return job.countFrames(status = DONE) < self.limit
class MinimumTimeBetweenDispatchPriority(PriorityRule): class MinimumTimeBetweenDispatchPriority(PriorityRule):
def str_limit(self): def str_limit(self):
return "more than %i minute%s since last" % (self.limit, "s" if self.limit > 1 else "") return "more than %i minute%s since last" % (self.limit, "s" if self.limit > 1 else "")
def __str__(self): def __str__(self):
return "Priority to jobs that haven't been dispatched recently" return "Priority to jobs that haven't been dispatched recently"
def __init__(self, limit = 10): def __init__(self, limit = 10):
self.limit = limit self.limit = limit
def test(self, job): def test(self, job):
return job.countFrames(status = DISPATCHED) == 0 and (time.time() - job.last_dispatched) / 60 > self.limit return job.countFrames(status = DISPATCHED) == 0 and (time.time() - job.last_dispatched) / 60 > self.limit
class ExcludeQueuedEmptyJob(ExclusionRule): class ExcludeQueuedEmptyJob(ExclusionRule):
def __str__(self): def __str__(self):
return "Exclude queued and empty jobs" return "Exclude queued and empty jobs"
def test(self, job):
return job.status != JOB_QUEUED or job.countFrames(status = QUEUED) == 0
class ExcludeSlavesLimit(ExclusionRule):
def str_limit(self):
return "more than %.0f%% of all slaves" % (self.limit * 100)
def __str__(self): def test(self, job):
return "Exclude jobs that would use too many slaves" return job.status != JOB_QUEUED or job.countFrames(status = QUEUED) == 0
def __init__(self, count_jobs, count_slaves, limit = 0.75): class ExcludeSlavesLimit(ExclusionRule):
self.count_jobs = count_jobs def str_limit(self):
self.count_slaves = count_slaves return "more than %.0f%% of all slaves" % (self.limit * 100)
self.limit = limit
def __str__(self):
def test(self, job): return "Exclude jobs that would use too many slaves"
return not ( self.count_jobs() == 1 or self.count_slaves() <= 1 or float(job.countSlaves() + 1) / self.count_slaves() <= self.limit )
def __init__(self, count_jobs, count_slaves, limit = 0.75):
self.count_jobs = count_jobs
self.count_slaves = count_slaves
self.limit = limit
def test(self, job):
return not ( self.count_jobs() == 1 or self.count_slaves() <= 1 or float(job.countSlaves() + 1) / self.count_slaves() <= self.limit )

View File

@@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, # along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@@ -28,253 +28,253 @@ import netrender.master as master
from netrender.utils import * from netrender.utils import *
def addFluidFiles(job, path): def addFluidFiles(job, path):
if os.path.exists(path): if os.path.exists(path):
pattern = re.compile("fluidsurface_(final|preview)_([0-9]+)\.(bobj|bvel)\.gz") pattern = re.compile("fluidsurface_(final|preview)_([0-9]+)\.(bobj|bvel)\.gz")
for fluid_file in sorted(os.listdir(path)): for fluid_file in sorted(os.listdir(path)):
match = pattern.match(fluid_file) match = pattern.match(fluid_file)
if match: if match:
# fluid frames starts at 0, which explains the +1 # fluid frames starts at 0, which explains the +1
# This is stupid # This is stupid
current_frame = int(match.groups()[1]) + 1 current_frame = int(match.groups()[1]) + 1
job.addFile(path + fluid_file, current_frame, current_frame) job.addFile(path + fluid_file, current_frame, current_frame)
def addPointCache(job, ob, point_cache, default_path): def addPointCache(job, ob, point_cache, default_path):
if not point_cache.disk_cache: if not point_cache.disk_cache:
return return
name = point_cache.name name = point_cache.name
if name == "": if name == "":
name = "".join(["%02X" % ord(c) for c in ob.name]) name = "".join(["%02X" % ord(c) for c in ob.name])
cache_path = bpy.utils.expandpath(point_cache.filepath) if point_cache.external else default_path cache_path = bpy.utils.expandpath(point_cache.filepath) if point_cache.external else default_path
index = "%02i" % point_cache.index index = "%02i" % point_cache.index
if os.path.exists(cache_path): if os.path.exists(cache_path):
pattern = re.compile(name + "_([0-9]+)_" + index + "\.bphys") pattern = re.compile(name + "_([0-9]+)_" + index + "\.bphys")
cache_files = [] cache_files = []
for cache_file in sorted(os.listdir(cache_path)):
match = pattern.match(cache_file)
if match:
cache_frame = int(match.groups()[0])
cache_files.append((cache_frame, cache_file))
cache_files.sort()
if len(cache_files) == 1:
cache_frame, cache_file = cache_files[0]
job.addFile(cache_path + cache_file, cache_frame, cache_frame)
else:
for i in range(len(cache_files)):
current_item = cache_files[i]
next_item = cache_files[i+1] if i + 1 < len(cache_files) else None
previous_item = cache_files[i - 1] if i > 0 else None
current_frame, current_file = current_item
if not next_item and not previous_item:
job.addFile(cache_path + current_file, current_frame, current_frame)
elif next_item and not previous_item:
next_frame = next_item[0]
job.addFile(cache_path + current_file, current_frame, next_frame - 1)
elif not next_item and previous_item:
previous_frame = previous_item[0]
job.addFile(cache_path + current_file, previous_frame + 1, current_frame)
else:
next_frame = next_item[0]
previous_frame = previous_item[0]
job.addFile(cache_path + current_file, previous_frame + 1, next_frame - 1)
for cache_file in sorted(os.listdir(cache_path)):
match = pattern.match(cache_file)
if match:
cache_frame = int(match.groups()[0])
cache_files.append((cache_frame, cache_file))
cache_files.sort()
if len(cache_files) == 1:
cache_frame, cache_file = cache_files[0]
job.addFile(cache_path + cache_file, cache_frame, cache_frame)
else:
for i in range(len(cache_files)):
current_item = cache_files[i]
next_item = cache_files[i+1] if i + 1 < len(cache_files) else None
previous_item = cache_files[i - 1] if i > 0 else None
current_frame, current_file = current_item
if not next_item and not previous_item:
job.addFile(cache_path + current_file, current_frame, current_frame)
elif next_item and not previous_item:
next_frame = next_item[0]
job.addFile(cache_path + current_file, current_frame, next_frame - 1)
elif not next_item and previous_item:
previous_frame = previous_item[0]
job.addFile(cache_path + current_file, previous_frame + 1, current_frame)
else:
next_frame = next_item[0]
previous_frame = previous_item[0]
job.addFile(cache_path + current_file, previous_frame + 1, next_frame - 1)
def clientSendJob(conn, scene, anim = False): def clientSendJob(conn, scene, anim = False):
netsettings = scene.network_render netsettings = scene.network_render
job = netrender.model.RenderJob() job = netrender.model.RenderJob()
if anim:
for f in range(scene.start_frame, scene.end_frame + 1):
job.addFrame(f)
else:
job.addFrame(scene.current_frame)
filename = bpy.data.filename
job.addFile(filename)
job_name = netsettings.job_name
path, name = os.path.split(filename)
if job_name == "[default]":
job_name = name
###########################
# LIBRARIES
###########################
for lib in bpy.data.libraries:
job.addFile(bpy.utils.expandpath(lib.filename))
###########################
# IMAGES
###########################
for image in bpy.data.images:
if image.source == "FILE" and not image.packed_file:
job.addFile(bpy.utils.expandpath(image.filename))
###########################
# FLUID + POINT CACHE
###########################
root, ext = os.path.splitext(name)
default_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that
for object in bpy.data.objects: if anim:
for modifier in object.modifiers: for f in range(scene.start_frame, scene.end_frame + 1):
if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN": job.addFrame(f)
addFluidFiles(job, bpy.utils.expandpath(modifier.settings.path)) else:
elif modifier.type == "CLOTH": job.addFrame(scene.current_frame)
addPointCache(job, object, modifier.point_cache, default_path)
elif modifier.type == "SOFT_BODY":
addPointCache(job, object, modifier.point_cache, default_path)
elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN":
addPointCache(job, object, modifier.domain_settings.point_cache_low, default_path)
if modifier.domain_settings.highres:
addPointCache(job, object, modifier.domain_settings.point_cache_high, default_path)
# particles modifier are stupid and don't contain data filename = bpy.data.filename
# we have to go through the object property job.addFile(filename)
for psys in object.particle_systems:
addPointCache(job, object, psys.point_cache, default_path) job_name = netsettings.job_name
path, name = os.path.split(filename)
#print(job.files) if job_name == "[default]":
job_name = name
job.name = job_name
job.category = netsettings.job_category ###########################
# LIBRARIES
for slave in netrender.blacklist: ###########################
job.blacklist.append(slave.id) for lib in bpy.data.libraries:
job.addFile(bpy.utils.expandpath(lib.filename))
job.chunks = netsettings.chunks
job.priority = netsettings.priority ###########################
# IMAGES
# try to send path first ###########################
conn.request("POST", "/job", repr(job.serialize())) for image in bpy.data.images:
response = conn.getresponse() if image.source == "FILE" and not image.packed_file:
job.addFile(bpy.utils.expandpath(image.filename))
job_id = response.getheader("job-id")
###########################
# if not ACCEPTED (but not processed), send files # FLUID + POINT CACHE
if response.status == http.client.ACCEPTED: ###########################
for rfile in job.files: root, ext = os.path.splitext(name)
f = open(rfile.filepath, "rb") default_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that
conn.request("PUT", fileURL(job_id, rfile.index), f)
f.close() for object in bpy.data.objects:
response = conn.getresponse() for modifier in object.modifiers:
if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN":
# server will reply with ACCEPTED until all files are found addFluidFiles(job, bpy.utils.expandpath(modifier.settings.path))
elif modifier.type == "CLOTH":
return job_id addPointCache(job, object, modifier.point_cache, default_path)
elif modifier.type == "SOFT_BODY":
addPointCache(job, object, modifier.point_cache, default_path)
elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN":
addPointCache(job, object, modifier.domain_settings.point_cache_low, default_path)
if modifier.domain_settings.highres:
addPointCache(job, object, modifier.domain_settings.point_cache_high, default_path)
# particles modifier are stupid and don't contain data
# we have to go through the object property
for psys in object.particle_systems:
addPointCache(job, object, psys.point_cache, default_path)
#print(job.files)
job.name = job_name
job.category = netsettings.job_category
for slave in netrender.blacklist:
job.blacklist.append(slave.id)
job.chunks = netsettings.chunks
job.priority = netsettings.priority
# try to send path first
conn.request("POST", "/job", repr(job.serialize()))
response = conn.getresponse()
job_id = response.getheader("job-id")
# if not ACCEPTED (but not processed), send files
if response.status == http.client.ACCEPTED:
for rfile in job.files:
f = open(rfile.filepath, "rb")
conn.request("PUT", fileURL(job_id, rfile.index), f)
f.close()
response = conn.getresponse()
# server will reply with ACCEPTED until all files are found
return job_id
def requestResult(conn, job_id, frame): def requestResult(conn, job_id, frame):
conn.request("GET", renderURL(job_id, frame)) conn.request("GET", renderURL(job_id, frame))
@rnaType @rnaType
class NetworkRenderEngine(bpy.types.RenderEngine): class NetworkRenderEngine(bpy.types.RenderEngine):
bl_idname = 'NET_RENDER' bl_idname = 'NET_RENDER'
bl_label = "Network Render" bl_label = "Network Render"
def render(self, scene): def render(self, scene):
if scene.network_render.mode == "RENDER_CLIENT": if scene.network_render.mode == "RENDER_CLIENT":
self.render_client(scene) self.render_client(scene)
elif scene.network_render.mode == "RENDER_SLAVE": elif scene.network_render.mode == "RENDER_SLAVE":
self.render_slave(scene) self.render_slave(scene)
elif scene.network_render.mode == "RENDER_MASTER": elif scene.network_render.mode == "RENDER_MASTER":
self.render_master(scene) self.render_master(scene)
else: else:
print("UNKNOWN OPERATION MODE") print("UNKNOWN OPERATION MODE")
def render_master(self, scene): def render_master(self, scene):
netsettings = scene.network_render netsettings = scene.network_render
address = "" if netsettings.server_address == "[default]" else netsettings.server_address address = "" if netsettings.server_address == "[default]" else netsettings.server_address
master.runMaster((address, netsettings.server_port), netsettings.server_broadcast, netsettings.path, self.update_stats, self.test_break) master.runMaster((address, netsettings.server_port), netsettings.server_broadcast, netsettings.path, self.update_stats, self.test_break)
def render_slave(self, scene): def render_slave(self, scene):
slave.render_slave(self, scene.network_render) slave.render_slave(self, scene.network_render)
def render_client(self, scene): def render_client(self, scene):
netsettings = scene.network_render netsettings = scene.network_render
self.update_stats("", "Network render client initiation") self.update_stats("", "Network render client initiation")
conn = clientConnection(netsettings.server_address, netsettings.server_port) conn = clientConnection(netsettings.server_address, netsettings.server_port)
if conn: if conn:
# Sending file # Sending file
self.update_stats("", "Network render exporting") self.update_stats("", "Network render exporting")
new_job = False new_job = False
job_id = netsettings.job_id job_id = netsettings.job_id
# reading back result # reading back result
self.update_stats("", "Network render waiting for results") self.update_stats("", "Network render waiting for results")
requestResult(conn, job_id, scene.current_frame) requestResult(conn, job_id, scene.current_frame)
response = conn.getresponse() response = conn.getresponse()
if response.status == http.client.NO_CONTENT: if response.status == http.client.NO_CONTENT:
new_job = True new_job = True
netsettings.job_id = clientSendJob(conn, scene) netsettings.job_id = clientSendJob(conn, scene)
job_id = netsettings.job_id job_id = netsettings.job_id
requestResult(conn, job_id, scene.current_frame) requestResult(conn, job_id, scene.current_frame)
response = conn.getresponse() response = conn.getresponse()
while response.status == http.client.ACCEPTED and not self.test_break(): while response.status == http.client.ACCEPTED and not self.test_break():
time.sleep(1) time.sleep(1)
requestResult(conn, job_id, scene.current_frame) requestResult(conn, job_id, scene.current_frame)
response = conn.getresponse() response = conn.getresponse()
# cancel new jobs (animate on network) on break # cancel new jobs (animate on network) on break
if self.test_break() and new_job: if self.test_break() and new_job:
conn.request("POST", cancelURL(job_id)) conn.request("POST", cancelURL(job_id))
response = conn.getresponse() response = conn.getresponse()
print( response.status, response.reason ) print( response.status, response.reason )
netsettings.job_id = 0 netsettings.job_id = 0
if response.status != http.client.OK: if response.status != http.client.OK:
conn.close() conn.close()
return return
r = scene.render_data r = scene.render_data
x= int(r.resolution_x*r.resolution_percentage*0.01) x= int(r.resolution_x*r.resolution_percentage*0.01)
y= int(r.resolution_y*r.resolution_percentage*0.01) y= int(r.resolution_y*r.resolution_percentage*0.01)
f = open(netsettings.path + "output.exr", "wb") f = open(netsettings.path + "output.exr", "wb")
buf = response.read(1024) buf = response.read(1024)
while buf: while buf:
f.write(buf) f.write(buf)
buf = response.read(1024) buf = response.read(1024)
f.close() f.close()
result = self.begin_result(0, 0, x, y) result = self.begin_result(0, 0, x, y)
result.load_from_file(netsettings.path + "output.exr", 0, 0) result.load_from_file(netsettings.path + "output.exr", 0, 0)
self.end_result(result) self.end_result(result)
conn.close() conn.close()
def compatible(module): def compatible(module):
module = __import__(module) module = __import__(module)
for subclass in module.__dict__.values(): for subclass in module.__dict__.values():
try: subclass.COMPAT_ENGINES.add('NET_RENDER') try: subclass.COMPAT_ENGINES.add('NET_RENDER')
except: pass except: pass
del module del module
compatible("properties_render") compatible("properties_render")
compatible("properties_world") compatible("properties_world")

File diff suppressed because it is too large Load Diff

View File

@@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, # along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@@ -24,226 +24,226 @@ from netrender.utils import *
src_folder = os.path.split(__file__)[0] src_folder = os.path.split(__file__)[0]
def get(handler): def get(handler):
def output(text): def output(text):
handler.wfile.write(bytes(text, encoding='utf8')) handler.wfile.write(bytes(text, encoding='utf8'))
def head(title): def head(title):
output("<html><head>") output("<html><head>")
output("<script src='/html/netrender.js' type='text/javascript'></script>") output("<script src='/html/netrender.js' type='text/javascript'></script>")
# output("<script src='/html/json2.js' type='text/javascript'></script>") # output("<script src='/html/json2.js' type='text/javascript'></script>")
output("<title>") output("<title>")
output(title) output(title)
output("</title></head><body>") output("</title></head><body>")
output("<link rel='stylesheet' href='/html/netrender.css' type='text/css'>") output("<link rel='stylesheet' href='/html/netrender.css' type='text/css'>")
def link(text, url):
return "<a href='%s'>%s</a>" % (url, text)
def startTable(border=1, class_style = None, caption = None):
output("<table border='%i'" % border)
if class_style:
output(" class='%s'" % class_style)
output(">")
if caption:
output("<caption>%s</caption>" % caption)
def headerTable(*headers):
output("<thead><tr>")
for c in headers:
output("<td>" + c + "</td>")
output("</tr></thead>")
def rowTable(*data, id = None, class_style = None, extra = None):
output("<tr")
if id:
output(" id='%s'" % id)
if class_style:
output(" class='%s'" % class_style)
if extra: def link(text, url):
output(" %s" % extra) return "<a href='%s'>%s</a>" % (url, text)
output(">") def startTable(border=1, class_style = None, caption = None):
output("<table border='%i'" % border)
for c in data:
output("<td>" + str(c) + "</td>")
output("</tr>")
def endTable():
output("</table>")
if handler.path == "/html/netrender.js":
f = open(os.path.join(src_folder, "netrender.js"), 'rb')
handler.send_head(content = "text/javascript")
shutil.copyfileobj(f, handler.wfile)
f.close()
elif handler.path == "/html/netrender.css":
f = open(os.path.join(src_folder, "netrender.css"), 'rb')
handler.send_head(content = "text/css")
shutil.copyfileobj(f, handler.wfile)
f.close()
elif handler.path == "/html" or handler.path == "/":
handler.send_head(content = "text/html")
head("NetRender")
output("<h2>Master</h2>")
output("""<button title="remove all jobs" onclick="request('/clear', null);">CLEAR JOB LIST</button>""")
startTable(caption = "Rules", class_style = "rules") if class_style:
output(" class='%s'" % class_style)
headerTable("type", "description", "limit") output(">")
for rule in handler.server.balancer.rules: if caption:
rowTable("rating", rule, rule.str_limit() if hasattr(rule, "limit") else "&nbsp;") output("<caption>%s</caption>" % caption)
for rule in handler.server.balancer.priorities: def headerTable(*headers):
rowTable("priority", rule, rule.str_limit() if hasattr(rule, "limit") else "&nbsp;") output("<thead><tr>")
for rule in handler.server.balancer.exceptions:
rowTable("exception", rule, rule.str_limit() if hasattr(rule, "limit") else "&nbsp;")
endTable() for c in headers:
output("<td>" + c + "</td>")
output("<h2>Slaves</h2>") output("</tr></thead>")
startTable()
headerTable("name", "address", "last seen", "stats", "job")
for slave in handler.server.slaves:
rowTable(slave.name, slave.address[0], time.ctime(slave.last_seen), slave.stats, link(slave.job.name, "/html/job" + slave.job.id) if slave.job else "None")
endTable()
output("<h2>Jobs</h2>")
startTable()
headerTable(
"&nbsp;",
"id",
"name",
"category",
"chunks",
"priority",
"usage",
"wait",
"status",
"length",
"done",
"dispatched",
"error",
"first",
"exception"
)
handler.server.balance() def rowTable(*data, id = None, class_style = None, extra = None):
output("<tr")
for job in handler.server.jobs:
results = job.framesStatus()
rowTable(
"""<button title="cancel job" onclick="request('/cancel_%s', null);">X</button>""" % job.id +
"""<button title="reset all frames" onclick="request('/resetall_%s_0', null);">R</button>""" % job.id,
job.id,
link(job.name, "/html/job" + job.id),
job.category if job.category else "<i>None</i>",
str(job.chunks) +
"""<button title="increase priority" onclick="request('/edit_%s', &quot;{'chunks': %i}&quot;);">+</button>""" % (job.id, job.chunks + 1) +
"""<button title="decrease priority" onclick="request('/edit_%s', &quot;{'chunks': %i}&quot;);" %s>-</button>""" % (job.id, job.chunks - 1, "disabled=True" if job.chunks == 1 else ""),
str(job.priority) +
"""<button title="increase chunks size" onclick="request('/edit_%s', &quot;{'priority': %i}&quot;);">+</button>""" % (job.id, job.priority + 1) +
"""<button title="decrease chunks size" onclick="request('/edit_%s', &quot;{'priority': %i}&quot;);" %s>-</button>""" % (job.id, job.priority - 1, "disabled=True" if job.priority == 1 else ""),
"%0.1f%%" % (job.usage * 100),
"%is" % int(time.time() - job.last_dispatched),
job.statusText(),
len(job),
results[DONE],
results[DISPATCHED],
str(results[ERROR]) +
"""<button title="reset error frames" onclick="request('/reset_%s_0', null);" %s>R</button>""" % (job.id, "disabled=True" if not results[ERROR] else ""),
handler.server.balancer.applyPriorities(job), handler.server.balancer.applyExceptions(job)
)
endTable()
output("</body></html>")
elif handler.path.startswith("/html/job"):
handler.send_head(content = "text/html")
job_id = handler.path[9:]
head("NetRender")
job = handler.server.getJobID(job_id)
if job:
output("<h2>Files</h2>")
startTable()
headerTable("path")
tot_cache = 0
tot_fluid = 0
for file in job.files:
if file.filepath.endswith(".bphys"):
tot_cache += 1
elif file.filepath.endswith(".bobj.gz") or file.filepath.endswith(".bvel.gz"):
tot_fluid += 1
else:
rowTable(file.filepath)
if tot_cache > 0: if id:
rowTable("%i physic cache files" % tot_cache, class_style = "toggle", extra = "onclick='toggleDisplay(&quot;.cache&quot;, &quot;none&quot;, &quot;table-row&quot;)'") output(" id='%s'" % id)
for file in job.files:
if file.filepath.endswith(".bphys"):
rowTable(os.path.split(file.filepath)[1], class_style = "cache")
if tot_fluid > 0:
rowTable("%i fluid bake files" % tot_fluid, class_style = "toggle", extra = "onclick='toggleDisplay(&quot;.fluid&quot;, &quot;none&quot;, &quot;table-row&quot;)'")
for file in job.files:
if file.filepath.endswith(".bobj.gz") or file.filepath.endswith(".bvel.gz"):
rowTable(os.path.split(file.filepath)[1], class_style = "fluid")
endTable() if class_style:
output(" class='%s'" % class_style)
output("<h2>Blacklist</h2>")
if job.blacklist:
startTable()
headerTable("name", "address")
for slave_id in job.blacklist:
slave = handler.server.slaves_map[slave_id]
rowTable(slave.name, slave.address[0])
endTable()
else:
output("<i>Empty</i>")
output("<h2>Frames</h2>") if extra:
output(" %s" % extra)
startTable()
headerTable("no", "status", "render time", "slave", "log", "result") output(">")
for frame in job.frames: for c in data:
rowTable(frame.number, frame.statusText(), "%.1fs" % frame.time, frame.slave.name if frame.slave else "&nbsp;", link("view log", logURL(job_id, frame.number)) if frame.log_path else "&nbsp;", link("view result", renderURL(job_id, frame.number)) if frame.status == DONE else "&nbsp;") output("<td>" + str(c) + "</td>")
endTable() output("</tr>")
else:
output("no such job") def endTable():
output("</table>")
output("</body></html>")
if handler.path == "/html/netrender.js":
f = open(os.path.join(src_folder, "netrender.js"), 'rb')
handler.send_head(content = "text/javascript")
shutil.copyfileobj(f, handler.wfile)
f.close()
elif handler.path == "/html/netrender.css":
f = open(os.path.join(src_folder, "netrender.css"), 'rb')
handler.send_head(content = "text/css")
shutil.copyfileobj(f, handler.wfile)
f.close()
elif handler.path == "/html" or handler.path == "/":
handler.send_head(content = "text/html")
head("NetRender")
output("<h2>Master</h2>")
output("""<button title="remove all jobs" onclick="request('/clear', null);">CLEAR JOB LIST</button>""")
startTable(caption = "Rules", class_style = "rules")
headerTable("type", "description", "limit")
for rule in handler.server.balancer.rules:
rowTable("rating", rule, rule.str_limit() if hasattr(rule, "limit") else "&nbsp;")
for rule in handler.server.balancer.priorities:
rowTable("priority", rule, rule.str_limit() if hasattr(rule, "limit") else "&nbsp;")
for rule in handler.server.balancer.exceptions:
rowTable("exception", rule, rule.str_limit() if hasattr(rule, "limit") else "&nbsp;")
endTable()
output("<h2>Slaves</h2>")
startTable()
headerTable("name", "address", "last seen", "stats", "job")
for slave in handler.server.slaves:
rowTable(slave.name, slave.address[0], time.ctime(slave.last_seen), slave.stats, link(slave.job.name, "/html/job" + slave.job.id) if slave.job else "None")
endTable()
output("<h2>Jobs</h2>")
startTable()
headerTable(
"&nbsp;",
"id",
"name",
"category",
"chunks",
"priority",
"usage",
"wait",
"status",
"length",
"done",
"dispatched",
"error",
"first",
"exception"
)
handler.server.balance()
for job in handler.server.jobs:
results = job.framesStatus()
rowTable(
"""<button title="cancel job" onclick="request('/cancel_%s', null);">X</button>""" % job.id +
"""<button title="reset all frames" onclick="request('/resetall_%s_0', null);">R</button>""" % job.id,
job.id,
link(job.name, "/html/job" + job.id),
job.category if job.category else "<i>None</i>",
str(job.chunks) +
"""<button title="increase priority" onclick="request('/edit_%s', &quot;{'chunks': %i}&quot;);">+</button>""" % (job.id, job.chunks + 1) +
"""<button title="decrease priority" onclick="request('/edit_%s', &quot;{'chunks': %i}&quot;);" %s>-</button>""" % (job.id, job.chunks - 1, "disabled=True" if job.chunks == 1 else ""),
str(job.priority) +
"""<button title="increase chunks size" onclick="request('/edit_%s', &quot;{'priority': %i}&quot;);">+</button>""" % (job.id, job.priority + 1) +
"""<button title="decrease chunks size" onclick="request('/edit_%s', &quot;{'priority': %i}&quot;);" %s>-</button>""" % (job.id, job.priority - 1, "disabled=True" if job.priority == 1 else ""),
"%0.1f%%" % (job.usage * 100),
"%is" % int(time.time() - job.last_dispatched),
job.statusText(),
len(job),
results[DONE],
results[DISPATCHED],
str(results[ERROR]) +
"""<button title="reset error frames" onclick="request('/reset_%s_0', null);" %s>R</button>""" % (job.id, "disabled=True" if not results[ERROR] else ""),
handler.server.balancer.applyPriorities(job), handler.server.balancer.applyExceptions(job)
)
endTable()
output("</body></html>")
elif handler.path.startswith("/html/job"):
handler.send_head(content = "text/html")
job_id = handler.path[9:]
head("NetRender")
job = handler.server.getJobID(job_id)
if job:
output("<h2>Files</h2>")
startTable()
headerTable("path")
tot_cache = 0
tot_fluid = 0
for file in job.files:
if file.filepath.endswith(".bphys"):
tot_cache += 1
elif file.filepath.endswith(".bobj.gz") or file.filepath.endswith(".bvel.gz"):
tot_fluid += 1
else:
rowTable(file.filepath)
if tot_cache > 0:
rowTable("%i physic cache files" % tot_cache, class_style = "toggle", extra = "onclick='toggleDisplay(&quot;.cache&quot;, &quot;none&quot;, &quot;table-row&quot;)'")
for file in job.files:
if file.filepath.endswith(".bphys"):
rowTable(os.path.split(file.filepath)[1], class_style = "cache")
if tot_fluid > 0:
rowTable("%i fluid bake files" % tot_fluid, class_style = "toggle", extra = "onclick='toggleDisplay(&quot;.fluid&quot;, &quot;none&quot;, &quot;table-row&quot;)'")
for file in job.files:
if file.filepath.endswith(".bobj.gz") or file.filepath.endswith(".bvel.gz"):
rowTable(os.path.split(file.filepath)[1], class_style = "fluid")
endTable()
output("<h2>Blacklist</h2>")
if job.blacklist:
startTable()
headerTable("name", "address")
for slave_id in job.blacklist:
slave = handler.server.slaves_map[slave_id]
rowTable(slave.name, slave.address[0])
endTable()
else:
output("<i>Empty</i>")
output("<h2>Frames</h2>")
startTable()
headerTable("no", "status", "render time", "slave", "log", "result")
for frame in job.frames:
rowTable(frame.number, frame.statusText(), "%.1fs" % frame.time, frame.slave.name if frame.slave else "&nbsp;", link("view log", logURL(job_id, frame.number)) if frame.log_path else "&nbsp;", link("view result", renderURL(job_id, frame.number)) if frame.status == DONE else "&nbsp;")
endTable()
else:
output("no such job")
output("</body></html>")

View File

@@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, # along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@@ -23,256 +23,256 @@ import subprocess, shutil, time, hashlib
from netrender.utils import * from netrender.utils import *
class LogFile: class LogFile:
def __init__(self, job_id = 0, slave_id = 0, frames = []): def __init__(self, job_id = 0, slave_id = 0, frames = []):
self.job_id = job_id self.job_id = job_id
self.slave_id = slave_id self.slave_id = slave_id
self.frames = frames self.frames = frames
def serialize(self): def serialize(self):
return { return {
"job_id": self.job_id, "job_id": self.job_id,
"slave_id": self.slave_id, "slave_id": self.slave_id,
"frames": self.frames "frames": self.frames
} }
@staticmethod @staticmethod
def materialize(data): def materialize(data):
if not data: if not data:
return None return None
logfile = LogFile() logfile = LogFile()
logfile.job_id = data["job_id"] logfile.job_id = data["job_id"]
logfile.slave_id = data["slave_id"] logfile.slave_id = data["slave_id"]
logfile.frames = data["frames"] logfile.frames = data["frames"]
return logfile return logfile
class RenderSlave: class RenderSlave:
_slave_map = {} _slave_map = {}
def __init__(self):
self.id = ""
self.name = ""
self.address = ("",0)
self.stats = ""
self.total_done = 0
self.total_error = 0
self.last_seen = 0.0
def serialize(self):
return {
"id": self.id,
"name": self.name,
"address": self.address,
"stats": self.stats,
"total_done": self.total_done,
"total_error": self.total_error,
"last_seen": self.last_seen
}
@staticmethod
def materialize(data, cache = True):
if not data:
return None
slave_id = data["id"]
if cache and slave_id in RenderSlave._slave_map: def __init__(self):
return RenderSlave._slave_map[slave_id] self.id = ""
self.name = ""
self.address = ("",0)
self.stats = ""
self.total_done = 0
self.total_error = 0
self.last_seen = 0.0
slave = RenderSlave() def serialize(self):
slave.id = slave_id return {
slave.name = data["name"] "id": self.id,
slave.address = data["address"] "name": self.name,
slave.stats = data["stats"] "address": self.address,
slave.total_done = data["total_done"] "stats": self.stats,
slave.total_error = data["total_error"] "total_done": self.total_done,
slave.last_seen = data["last_seen"] "total_error": self.total_error,
"last_seen": self.last_seen
}
if cache: @staticmethod
RenderSlave._slave_map[slave_id] = slave def materialize(data, cache = True):
if not data:
return slave return None
slave_id = data["id"]
if cache and slave_id in RenderSlave._slave_map:
return RenderSlave._slave_map[slave_id]
slave = RenderSlave()
slave.id = slave_id
slave.name = data["name"]
slave.address = data["address"]
slave.stats = data["stats"]
slave.total_done = data["total_done"]
slave.total_error = data["total_error"]
slave.last_seen = data["last_seen"]
if cache:
RenderSlave._slave_map[slave_id] = slave
return slave
JOB_BLENDER = 1 JOB_BLENDER = 1
JOB_PROCESS = 2 JOB_PROCESS = 2
JOB_TYPES = { JOB_TYPES = {
JOB_BLENDER: "Blender", JOB_BLENDER: "Blender",
JOB_PROCESS: "Process" JOB_PROCESS: "Process"
} }
class RenderFile: class RenderFile:
def __init__(self, filepath = "", index = 0, start = -1, end = -1): def __init__(self, filepath = "", index = 0, start = -1, end = -1):
self.filepath = filepath self.filepath = filepath
self.index = index self.index = index
self.start = start self.start = start
self.end = end self.end = end
def serialize(self): def serialize(self):
return { return {
"filepath": self.filepath, "filepath": self.filepath,
"index": self.index, "index": self.index,
"start": self.start, "start": self.start,
"end": self.end "end": self.end
} }
@staticmethod @staticmethod
def materialize(data): def materialize(data):
if not data: if not data:
return None return None
rfile = RenderFile(data["filepath"], data["index"], data["start"], data["end"])
return rfile rfile = RenderFile(data["filepath"], data["index"], data["start"], data["end"])
return rfile
class RenderJob: class RenderJob:
def __init__(self, job_info = None): def __init__(self, job_info = None):
self.id = "" self.id = ""
self.type = JOB_BLENDER self.type = JOB_BLENDER
self.name = "" self.name = ""
self.category = "None" self.category = "None"
self.status = JOB_WAITING self.status = JOB_WAITING
self.files = [] self.files = []
self.chunks = 0 self.chunks = 0
self.priority = 0 self.priority = 0
self.blacklist = [] self.blacklist = []
self.usage = 0.0 self.usage = 0.0
self.last_dispatched = 0.0 self.last_dispatched = 0.0
self.frames = [] self.frames = []
if job_info:
self.type = job_info.type
self.name = job_info.name
self.category = job_info.category
self.status = job_info.status
self.files = job_info.files
self.chunks = job_info.chunks
self.priority = job_info.priority
self.blacklist = job_info.blacklist
def addFile(self, file_path, start=-1, end=-1):
self.files.append(RenderFile(file_path, len(self.files), start, end))
def addFrame(self, frame_number, command = ""):
frame = RenderFrame(frame_number, command)
self.frames.append(frame)
return frame
def __len__(self):
return len(self.frames)
def countFrames(self, status=QUEUED):
total = 0
for f in self.frames:
if f.status == status:
total += 1
return total
def countSlaves(self):
return len(set((frame.slave for frame in self.frames if frame.status == DISPATCHED)))
def statusText(self):
return JOB_STATUS_TEXT[self.status]
def framesStatus(self):
results = {
QUEUED: 0,
DISPATCHED: 0,
DONE: 0,
ERROR: 0
}
for frame in self.frames:
results[frame.status] += 1
return results
def __contains__(self, frame_number):
for f in self.frames:
if f.number == frame_number:
return True
else:
return False
def __getitem__(self, frame_number):
for f in self.frames:
if f.number == frame_number:
return f
else:
return None
def serialize(self, frames = None):
min_frame = min((f.number for f in frames)) if frames else -1
max_frame = max((f.number for f in frames)) if frames else -1
return {
"id": self.id,
"type": self.type,
"name": self.name,
"category": self.category,
"status": self.status,
"files": [f.serialize() for f in self.files if f.start == -1 or not frames or (f.start <= max_frame and f.end >= min_frame)],
"frames": [f.serialize() for f in self.frames if not frames or f in frames],
"chunks": self.chunks,
"priority": self.priority,
"usage": self.usage,
"blacklist": self.blacklist,
"last_dispatched": self.last_dispatched
}
@staticmethod if job_info:
def materialize(data): self.type = job_info.type
if not data: self.name = job_info.name
return None self.category = job_info.category
self.status = job_info.status
job = RenderJob() self.files = job_info.files
job.id = data["id"] self.chunks = job_info.chunks
job.type = data["type"] self.priority = job_info.priority
job.name = data["name"] self.blacklist = job_info.blacklist
job.category = data["category"]
job.status = data["status"]
job.files = [RenderFile.materialize(f) for f in data["files"]]
job.frames = [RenderFrame.materialize(f) for f in data["frames"]]
job.chunks = data["chunks"]
job.priority = data["priority"]
job.usage = data["usage"]
job.blacklist = data["blacklist"]
job.last_dispatched = data["last_dispatched"]
return job def addFile(self, file_path, start=-1, end=-1):
self.files.append(RenderFile(file_path, len(self.files), start, end))
def addFrame(self, frame_number, command = ""):
frame = RenderFrame(frame_number, command)
self.frames.append(frame)
return frame
def __len__(self):
return len(self.frames)
def countFrames(self, status=QUEUED):
total = 0
for f in self.frames:
if f.status == status:
total += 1
return total
def countSlaves(self):
return len(set((frame.slave for frame in self.frames if frame.status == DISPATCHED)))
def statusText(self):
return JOB_STATUS_TEXT[self.status]
def framesStatus(self):
results = {
QUEUED: 0,
DISPATCHED: 0,
DONE: 0,
ERROR: 0
}
for frame in self.frames:
results[frame.status] += 1
return results
def __contains__(self, frame_number):
for f in self.frames:
if f.number == frame_number:
return True
else:
return False
def __getitem__(self, frame_number):
for f in self.frames:
if f.number == frame_number:
return f
else:
return None
def serialize(self, frames = None):
min_frame = min((f.number for f in frames)) if frames else -1
max_frame = max((f.number for f in frames)) if frames else -1
return {
"id": self.id,
"type": self.type,
"name": self.name,
"category": self.category,
"status": self.status,
"files": [f.serialize() for f in self.files if f.start == -1 or not frames or (f.start <= max_frame and f.end >= min_frame)],
"frames": [f.serialize() for f in self.frames if not frames or f in frames],
"chunks": self.chunks,
"priority": self.priority,
"usage": self.usage,
"blacklist": self.blacklist,
"last_dispatched": self.last_dispatched
}
@staticmethod
def materialize(data):
if not data:
return None
job = RenderJob()
job.id = data["id"]
job.type = data["type"]
job.name = data["name"]
job.category = data["category"]
job.status = data["status"]
job.files = [RenderFile.materialize(f) for f in data["files"]]
job.frames = [RenderFrame.materialize(f) for f in data["frames"]]
job.chunks = data["chunks"]
job.priority = data["priority"]
job.usage = data["usage"]
job.blacklist = data["blacklist"]
job.last_dispatched = data["last_dispatched"]
return job
class RenderFrame: class RenderFrame:
def __init__(self, number = 0, command = ""): def __init__(self, number = 0, command = ""):
self.number = number self.number = number
self.time = 0 self.time = 0
self.status = QUEUED self.status = QUEUED
self.slave = None self.slave = None
self.command = command self.command = command
def statusText(self): def statusText(self):
return FRAME_STATUS_TEXT[self.status] return FRAME_STATUS_TEXT[self.status]
def serialize(self): def serialize(self):
return { return {
"number": self.number, "number": self.number,
"time": self.time, "time": self.time,
"status": self.status, "status": self.status,
"slave": None if not self.slave else self.slave.serialize(), "slave": None if not self.slave else self.slave.serialize(),
"command": self.command "command": self.command
} }
@staticmethod
def materialize(data):
if not data:
return None
frame = RenderFrame()
frame.number = data["number"]
frame.time = data["time"]
frame.status = data["status"]
frame.slave = RenderSlave.materialize(data["slave"])
frame.command = data["command"]
return frame @staticmethod
def materialize(data):
if not data:
return None
frame = RenderFrame()
frame.number = data["number"]
frame.time = data["time"]
frame.status = data["status"]
frame.slave = RenderSlave.materialize(data["slave"])
frame.command = data["command"]
return frame

View File

@@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, # along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@@ -26,413 +26,416 @@ from netrender.utils import *
import netrender.client as client import netrender.client as client
import netrender.model import netrender.model
@rnaOperator @rnaType
class RENDER_OT_netslave_bake(bpy.types.Operator): class RENDER_OT_netslave_bake(bpy.types.Operator):
'''NEED DESCRIPTION''' '''NEED DESCRIPTION'''
bl_idname = "render.netslavebake" bl_idname = "render.netslavebake"
bl_label = "Bake all in file" bl_label = "Bake all in file"
def poll(self, context): def poll(self, context):
return True return True
def execute(self, context): def execute(self, context):
scene = context.scene scene = context.scene
netsettings = scene.network_render netsettings = scene.network_render
filename = bpy.data.filename filename = bpy.data.filename
path, name = os.path.split(filename) path, name = os.path.split(filename)
root, ext = os.path.splitext(name) root, ext = os.path.splitext(name)
default_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that default_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that
relative_path = os.sep + os.sep + "blendcache_" + root + os.sep relative_path = os.sep + os.sep + "blendcache_" + root + os.sep
# Force all point cache next to the blend file # Force all point cache next to the blend file
for object in bpy.data.objects: for object in bpy.data.objects:
for modifier in object.modifiers: for modifier in object.modifiers:
if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN": if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN":
modifier.settings.path = relative_path modifier.settings.path = relative_path
bpy.ops.fluid.bake({"active_object": object, "scene": scene}) bpy.ops.fluid.bake({"active_object": object, "scene": scene})
elif modifier.type == "CLOTH": elif modifier.type == "CLOTH":
modifier.point_cache.step = 1 modifier.point_cache.step = 1
modifier.point_cache.disk_cache = True modifier.point_cache.disk_cache = True
modifier.point_cache.external = False modifier.point_cache.external = False
elif modifier.type == "SOFT_BODY": elif modifier.type == "SOFT_BODY":
modifier.point_cache.step = 1 modifier.point_cache.step = 1
modifier.point_cache.disk_cache = True modifier.point_cache.disk_cache = True
modifier.point_cache.external = False modifier.point_cache.external = False
elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN": elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN":
modifier.domain_settings.point_cache_low.step = 1 modifier.domain_settings.point_cache_low.step = 1
modifier.domain_settings.point_cache_low.disk_cache = True modifier.domain_settings.point_cache_low.disk_cache = True
modifier.domain_settings.point_cache_low.external = False modifier.domain_settings.point_cache_low.external = False
modifier.domain_settings.point_cache_high.step = 1 modifier.domain_settings.point_cache_high.step = 1
modifier.domain_settings.point_cache_high.disk_cache = True modifier.domain_settings.point_cache_high.disk_cache = True
modifier.domain_settings.point_cache_high.external = False modifier.domain_settings.point_cache_high.external = False
# particles modifier are stupid and don't contain data # particles modifier are stupid and don't contain data
# we have to go through the object property # we have to go through the object property
for psys in object.particle_systems: for psys in object.particle_systems:
psys.point_cache.step = 1 psys.point_cache.step = 1
psys.point_cache.disk_cache = True psys.point_cache.disk_cache = True
psys.point_cache.external = False psys.point_cache.external = False
psys.point_cache.filepath = relative_path psys.point_cache.filepath = relative_path
bpy.ops.ptcache.bake_all() bpy.ops.ptcache.bake_all()
#bpy.ops.wm.save_mainfile(path = path + os.sep + root + "_baked.blend") #bpy.ops.wm.save_mainfile(path = path + os.sep + root + "_baked.blend")
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
return self.execute(context) return self.execute(context)
@rnaOperator @rnaType
class RENDER_OT_netclientanim(bpy.types.Operator): class RENDER_OT_netclientanim(bpy.types.Operator):
'''Start rendering an animation on network''' '''Start rendering an animation on network'''
bl_idname = "render.netclientanim" bl_idname = "render.netclientanim"
bl_label = "Animation on network" bl_label = "Animation on network"
def poll(self, context):
return True
def execute(self, context):
scene = context.scene
netsettings = scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn: def poll(self, context):
# Sending file return True
scene.network_render.job_id = client.clientSendJob(conn, scene, True)
conn.close()
bpy.ops.screen.render('INVOKE_AREA', animation=True)
return ('FINISHED',)
def invoke(self, context, event):
return self.execute(context)
@rnaOperator def execute(self, context):
scene = context.scene
netsettings = scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
# Sending file
scene.network_render.job_id = client.clientSendJob(conn, scene, True)
conn.close()
bpy.ops.screen.render('INVOKE_AREA', animation=True)
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class RENDER_OT_netclientsend(bpy.types.Operator): class RENDER_OT_netclientsend(bpy.types.Operator):
'''Send Render Job to the Network''' '''Send Render Job to the Network'''
bl_idname = "render.netclientsend" bl_idname = "render.netclientsend"
bl_label = "Send job" bl_label = "Send job"
def poll(self, context):
return True
def execute(self, context):
scene = context.scene
netsettings = scene.network_render
try:
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn: def poll(self, context):
# Sending file return True
scene.network_render.job_id = client.clientSendJob(conn, scene, True)
conn.close()
self.report('INFO', "Job sent to master")
except Exception as err:
self.report('ERROR', str(err))
return ('FINISHED',)
def invoke(self, context, event):
return self.execute(context)
@rnaOperator def execute(self, context):
scene = context.scene
netsettings = scene.network_render
try:
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
# Sending file
scene.network_render.job_id = client.clientSendJob(conn, scene, True)
conn.close()
self.report('INFO', "Job sent to master")
except Exception as err:
self.report('ERROR', str(err))
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class RENDER_OT_netclientstatus(bpy.types.Operator): class RENDER_OT_netclientstatus(bpy.types.Operator):
'''Refresh the status of the current jobs''' '''Refresh the status of the current jobs'''
bl_idname = "render.netclientstatus" bl_idname = "render.netclientstatus"
bl_label = "Client Status" bl_label = "Client Status"
def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn: def poll(self, context):
conn.request("GET", "/status") return True
response = conn.getresponse()
print( response.status, response.reason )
jobs = (netrender.model.RenderJob.materialize(j) for j in eval(str(response.read(), encoding='utf8')))
while(len(netsettings.jobs) > 0):
netsettings.jobs.remove(0)
netrender.jobs = []
for j in jobs:
netrender.jobs.append(j)
netsettings.jobs.add()
job = netsettings.jobs[-1]
j.results = j.framesStatus() # cache frame status
job.name = j.name
return ('FINISHED',)
def invoke(self, context, event):
return self.execute(context)
@rnaOperator def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.request("GET", "/status")
response = conn.getresponse()
print( response.status, response.reason )
jobs = (netrender.model.RenderJob.materialize(j) for j in eval(str(response.read(), encoding='utf8')))
while(len(netsettings.jobs) > 0):
netsettings.jobs.remove(0)
netrender.jobs = []
for j in jobs:
netrender.jobs.append(j)
netsettings.jobs.add()
job = netsettings.jobs[-1]
j.results = j.framesStatus() # cache frame status
job.name = j.name
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class RENDER_OT_netclientblacklistslave(bpy.types.Operator): class RENDER_OT_netclientblacklistslave(bpy.types.Operator):
'''Operator documentation text, will be used for the operator tooltip and python docs.''' '''Operator documentation text, will be used for the operator tooltip and python docs.'''
bl_idname = "render.netclientblacklistslave" bl_idname = "render.netclientblacklistslave"
bl_label = "Client Blacklist Slave" bl_label = "Client Blacklist Slave"
def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
if netsettings.active_slave_index >= 0:
# deal with data
slave = netrender.slaves.pop(netsettings.active_slave_index)
netrender.blacklist.append(slave)
# deal with rna
netsettings.slaves_blacklist.add()
netsettings.slaves_blacklist[-1].name = slave.name
netsettings.slaves.remove(netsettings.active_slave_index)
netsettings.active_slave_index = -1
return ('FINISHED',)
def invoke(self, context, event):
return self.execute(context)
@rnaOperator def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
if netsettings.active_slave_index >= 0:
# deal with data
slave = netrender.slaves.pop(netsettings.active_slave_index)
netrender.blacklist.append(slave)
# deal with rna
netsettings.slaves_blacklist.add()
netsettings.slaves_blacklist[-1].name = slave.name
netsettings.slaves.remove(netsettings.active_slave_index)
netsettings.active_slave_index = -1
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class RENDER_OT_netclientwhitelistslave(bpy.types.Operator): class RENDER_OT_netclientwhitelistslave(bpy.types.Operator):
'''Operator documentation text, will be used for the operator tooltip and python docs.''' '''Operator documentation text, will be used for the operator tooltip and python docs.'''
bl_idname = "render.netclientwhitelistslave" bl_idname = "render.netclientwhitelistslave"
bl_label = "Client Whitelist Slave" bl_label = "Client Whitelist Slave"
def poll(self, context): def poll(self, context):
return True return True
def execute(self, context): def execute(self, context):
netsettings = context.scene.network_render netsettings = context.scene.network_render
if netsettings.active_blacklisted_slave_index >= 0: if netsettings.active_blacklisted_slave_index >= 0:
# deal with data # deal with data
slave = netrender.blacklist.pop(netsettings.active_blacklisted_slave_index) slave = netrender.blacklist.pop(netsettings.active_blacklisted_slave_index)
netrender.slaves.append(slave) netrender.slaves.append(slave)
# deal with rna # deal with rna
netsettings.slaves.add() netsettings.slaves.add()
netsettings.slaves[-1].name = slave.name netsettings.slaves[-1].name = slave.name
netsettings.slaves_blacklist.remove(netsettings.active_blacklisted_slave_index) netsettings.slaves_blacklist.remove(netsettings.active_blacklisted_slave_index)
netsettings.active_blacklisted_slave_index = -1 netsettings.active_blacklisted_slave_index = -1
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
return self.execute(context) return self.execute(context)
@rnaOperator @rnaType
class RENDER_OT_netclientslaves(bpy.types.Operator): class RENDER_OT_netclientslaves(bpy.types.Operator):
'''Refresh status about available Render slaves''' '''Refresh status about available Render slaves'''
bl_idname = "render.netclientslaves" bl_idname = "render.netclientslaves"
bl_label = "Client Slaves" bl_label = "Client Slaves"
def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.request("GET", "/slaves")
response = conn.getresponse()
print( response.status, response.reason )
slaves = (netrender.model.RenderSlave.materialize(s) for s in eval(str(response.read(), encoding='utf8')))
while(len(netsettings.slaves) > 0):
netsettings.slaves.remove(0)
netrender.slaves = []
for s in slaves:
for i in range(len(netrender.blacklist)):
slave = netrender.blacklist[i]
if slave.id == s.id:
netrender.blacklist[i] = s
netsettings.slaves_blacklist[i].name = s.name
break
else:
netrender.slaves.append(s)
netsettings.slaves.add()
slave = netsettings.slaves[-1]
slave.name = s.name
return ('FINISHED',)
def invoke(self, context, event):
return self.execute(context)
@rnaOperator def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.request("GET", "/slaves")
response = conn.getresponse()
print( response.status, response.reason )
slaves = (netrender.model.RenderSlave.materialize(s) for s in eval(str(response.read(), encoding='utf8')))
while(len(netsettings.slaves) > 0):
netsettings.slaves.remove(0)
netrender.slaves = []
for s in slaves:
for i in range(len(netrender.blacklist)):
slave = netrender.blacklist[i]
if slave.id == s.id:
netrender.blacklist[i] = s
netsettings.slaves_blacklist[i].name = s.name
break
else:
netrender.slaves.append(s)
netsettings.slaves.add()
slave = netsettings.slaves[-1]
slave.name = s.name
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class RENDER_OT_netclientcancel(bpy.types.Operator): class RENDER_OT_netclientcancel(bpy.types.Operator):
'''Cancel the selected network rendering job.''' '''Cancel the selected network rendering job.'''
bl_idname = "render.netclientcancel" bl_idname = "render.netclientcancel"
bl_label = "Client Cancel" bl_label = "Client Cancel"
def poll(self, context):
netsettings = context.scene.network_render
return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
job = netrender.jobs[netsettings.active_job_index]
conn.request("POST", cancelURL(job.id))
response = conn.getresponse()
print( response.status, response.reason )
netsettings.jobs.remove(netsettings.active_job_index) def poll(self, context):
netsettings = context.scene.network_render
return ('FINISHED',) return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
def invoke(self, context, event): def execute(self, context):
return self.execute(context) netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
@rnaOperator
if conn:
job = netrender.jobs[netsettings.active_job_index]
conn.request("POST", cancelURL(job.id))
response = conn.getresponse()
print( response.status, response.reason )
netsettings.jobs.remove(netsettings.active_job_index)
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class RENDER_OT_netclientcancelall(bpy.types.Operator): class RENDER_OT_netclientcancelall(bpy.types.Operator):
'''Cancel all running network rendering jobs.''' '''Cancel all running network rendering jobs.'''
bl_idname = "render.netclientcancelall" bl_idname = "render.netclientcancelall"
bl_label = "Client Cancel All" bl_label = "Client Cancel All"
def poll(self, context):
return True
def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.request("POST", "/clear")
response = conn.getresponse()
print( response.status, response.reason )
while(len(netsettings.jobs) > 0):
netsettings.jobs.remove(0)
return ('FINISHED',) def poll(self, context):
return True
def invoke(self, context, event):
return self.execute(context)
@rnaOperator def execute(self, context):
netsettings = context.scene.network_render
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.request("POST", "/clear")
response = conn.getresponse()
print( response.status, response.reason )
while(len(netsettings.jobs) > 0):
netsettings.jobs.remove(0)
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class netclientdownload(bpy.types.Operator): class netclientdownload(bpy.types.Operator):
'''Download render results from the network''' '''Download render results from the network'''
bl_idname = "render.netclientdownload" bl_idname = "render.netclientdownload"
bl_label = "Client Download" bl_label = "Client Download"
def poll(self, context):
netsettings = context.scene.network_render
return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
def execute(self, context):
netsettings = context.scene.network_render
rd = context.scene.render_data
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
job = netrender.jobs[netsettings.active_job_index]
for frame in job.frames:
client.requestResult(conn, job.id, frame.number)
response = conn.getresponse()
if response.status != http.client.OK:
print("missing", frame.number)
continue
print("got back", frame.number)
f = open(netsettings.path + "%06d" % frame.number + ".exr", "wb")
buf = response.read(1024)
while buf:
f.write(buf)
buf = response.read(1024)
f.close()
conn.close()
return ('FINISHED',)
def invoke(self, context, event):
return self.execute(context)
@rnaOperator def poll(self, context):
netsettings = context.scene.network_render
return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
def execute(self, context):
netsettings = context.scene.network_render
rd = context.scene.render_data
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
job = netrender.jobs[netsettings.active_job_index]
for frame in job.frames:
client.requestResult(conn, job.id, frame.number)
response = conn.getresponse()
if response.status != http.client.OK:
print("missing", frame.number)
continue
print("got back", frame.number)
f = open(netsettings.path + "%06d" % frame.number + ".exr", "wb")
buf = response.read(1024)
while buf:
f.write(buf)
buf = response.read(1024)
f.close()
conn.close()
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@rnaType
class netclientscan(bpy.types.Operator): class netclientscan(bpy.types.Operator):
'''Operator documentation text, will be used for the operator tooltip and python docs.''' __slots__ = []
bl_idname = "render.netclientscan" '''Operator documentation text, will be used for the operator tooltip and python docs.'''
bl_label = "Client Scan" bl_idname = "render.netclientscan"
bl_label = "Client Scan"
def poll(self, context):
return True
def execute(self, context):
address, port = clientScan(self.report)
if address: def poll(self, context):
scene = context.scene return True
netsettings = scene.network_render
netsettings.server_address = address
netsettings.server_port = port
return ('FINISHED',)
def invoke(self, context, event): def execute(self, context):
return self.execute(context) address, port = clientScan(self.report)
@rnaOperator if address:
scene = context.scene
netsettings = scene.network_render
netsettings.server_address = address
netsettings.server_port = port
return {'FINISHED'}
def invoke(self, context, event):
print(dir(self))
return self.execute(context)
@rnaType
class netclientweb(bpy.types.Operator): class netclientweb(bpy.types.Operator):
'''Open new window with information about running rendering jobs''' '''Open new window with information about running rendering jobs'''
bl_idname = "render.netclientweb" bl_idname = "render.netclientweb"
bl_label = "Open Master Monitor" bl_label = "Open Master Monitor"
def poll(self, context): def poll(self, context):
return True netsettings = context.scene.network_render
return netsettings.server_address != "[default]"
def execute(self, context):
netsettings = context.scene.network_render def execute(self, context):
netsettings = context.scene.network_render
# open connection to make sure server exists
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report) # open connection to make sure server exists
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
conn.close() if conn:
conn.close()
webbrowser.open("http://%s:%i" % (netsettings.server_address, netsettings.server_port))
webbrowser.open("http://%s:%i" % (netsettings.server_address, netsettings.server_port))
return ('FINISHED',)
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context) def invoke(self, context, event):
return self.execute(context)

View File

@@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, # along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@@ -30,218 +30,218 @@ MAX_TIMEOUT = 10
INCREMENT_TIMEOUT = 1 INCREMENT_TIMEOUT = 1
if platform.system() == 'Windows' and platform.version() >= '5': # Error mode is only available on Win2k or higher, that's version 5 if platform.system() == 'Windows' and platform.version() >= '5': # Error mode is only available on Win2k or higher, that's version 5
import ctypes import ctypes
def SetErrorMode(): def SetErrorMode():
val = ctypes.windll.kernel32.SetErrorMode(0x0002) val = ctypes.windll.kernel32.SetErrorMode(0x0002)
ctypes.windll.kernel32.SetErrorMode(val | 0x0002) ctypes.windll.kernel32.SetErrorMode(val | 0x0002)
return val return val
def RestoreErrorMode(val): def RestoreErrorMode(val):
ctypes.windll.kernel32.SetErrorMode(val) ctypes.windll.kernel32.SetErrorMode(val)
else: else:
def SetErrorMode(): def SetErrorMode():
return 0 return 0
def RestoreErrorMode(val): def RestoreErrorMode(val):
pass pass
def slave_Info(): def slave_Info():
sysname, nodename, release, version, machine, processor = platform.uname() sysname, nodename, release, version, machine, processor = platform.uname()
slave = netrender.model.RenderSlave() slave = netrender.model.RenderSlave()
slave.name = nodename slave.name = nodename
slave.stats = sysname + " " + release + " " + machine + " " + processor slave.stats = sysname + " " + release + " " + machine + " " + processor
return slave return slave
def testCancel(conn, job_id, frame_number): def testCancel(conn, job_id, frame_number):
conn.request("HEAD", "/status", headers={"job-id":job_id, "job-frame": str(frame_number)}) conn.request("HEAD", "/status", headers={"job-id":job_id, "job-frame": str(frame_number)})
# cancelled if job isn't found anymore # cancelled if job isn't found anymore
if conn.getresponse().status == http.client.NO_CONTENT: if conn.getresponse().status == http.client.NO_CONTENT:
return True return True
else: else:
return False return False
def testFile(conn, job_id, slave_id, file_index, JOB_PREFIX, file_path, main_path = None): def testFile(conn, job_id, slave_id, file_index, JOB_PREFIX, file_path, main_path = None):
job_full_path = prefixPath(JOB_PREFIX, file_path, main_path) job_full_path = prefixPath(JOB_PREFIX, file_path, main_path)
if not os.path.exists(job_full_path): if not os.path.exists(job_full_path):
temp_path = JOB_PREFIX + "slave.temp.blend" temp_path = JOB_PREFIX + "slave.temp.blend"
conn.request("GET", fileURL(job_id, file_index), headers={"slave-id":slave_id}) conn.request("GET", fileURL(job_id, file_index), headers={"slave-id":slave_id})
response = conn.getresponse() response = conn.getresponse()
if response.status != http.client.OK: if response.status != http.client.OK:
return None # file for job not returned by server, need to return an error code to server return None # file for job not returned by server, need to return an error code to server
f = open(temp_path, "wb") f = open(temp_path, "wb")
buf = response.read(1024) buf = response.read(1024)
while buf: while buf:
f.write(buf) f.write(buf)
buf = response.read(1024) buf = response.read(1024)
f.close() f.close()
os.renames(temp_path, job_full_path) os.renames(temp_path, job_full_path)
return job_full_path return job_full_path
def render_slave(engine, netsettings): def render_slave(engine, netsettings):
timeout = 1 timeout = 1
engine.update_stats("", "Network render node initiation")
conn = clientConnection(netsettings.server_address, netsettings.server_port)
if conn:
conn.request("POST", "/slave", repr(slave_Info().serialize()))
response = conn.getresponse()
slave_id = response.getheader("slave-id")
NODE_PREFIX = netsettings.path + "slave_" + slave_id + os.sep
if not os.path.exists(NODE_PREFIX):
os.mkdir(NODE_PREFIX)
while not engine.test_break():
conn.request("GET", "/job", headers={"slave-id":slave_id})
response = conn.getresponse()
if response.status == http.client.OK:
timeout = 1 # reset timeout on new job
job = netrender.model.RenderJob.materialize(eval(str(response.read(), encoding='utf8')))
JOB_PREFIX = NODE_PREFIX + "job_" + job.id + os.sep
if not os.path.exists(JOB_PREFIX):
os.mkdir(JOB_PREFIX)
if job.type == netrender.model.JOB_BLENDER:
job_path = job.files[0].filepath # path of main file
main_path, main_file = os.path.split(job_path)
job_full_path = testFile(conn, job.id, slave_id, 0, JOB_PREFIX, job_path)
print("Fullpath", job_full_path)
print("File:", main_file, "and %i other files" % (len(job.files) - 1,))
engine.update_stats("", "Render File "+ main_file+ " for job "+ job.id)
for rfile in job.files[1:]:
print("\t", rfile.filepath)
testFile(conn, job.id, slave_id, rfile.index, JOB_PREFIX, rfile.filepath, main_path)
# announce log to master engine.update_stats("", "Network render node initiation")
logfile = netrender.model.LogFile(job.id, slave_id, [frame.number for frame in job.frames])
conn.request("POST", "/log", bytes(repr(logfile.serialize()), encoding='utf8')) conn = clientConnection(netsettings.server_address, netsettings.server_port)
response = conn.getresponse()
if conn:
conn.request("POST", "/slave", repr(slave_Info().serialize()))
first_frame = job.frames[0].number response = conn.getresponse()
# start render slave_id = response.getheader("slave-id")
start_t = time.time()
NODE_PREFIX = netsettings.path + "slave_" + slave_id + os.sep
if job.type == netrender.model.JOB_BLENDER: if not os.path.exists(NODE_PREFIX):
frame_args = [] os.mkdir(NODE_PREFIX)
for frame in job.frames: while not engine.test_break():
print("frame", frame.number)
frame_args += ["-f", str(frame.number)] conn.request("GET", "/job", headers={"slave-id":slave_id})
response = conn.getresponse()
val = SetErrorMode()
process = subprocess.Popen([BLENDER_PATH, "-b", "-noaudio", job_full_path, "-o", JOB_PREFIX + "######", "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if response.status == http.client.OK:
RestoreErrorMode(val) timeout = 1 # reset timeout on new job
elif job.type == netrender.model.JOB_PROCESS:
command = job.frames[0].command job = netrender.model.RenderJob.materialize(eval(str(response.read(), encoding='utf8')))
val = SetErrorMode()
process = subprocess.Popen(command.split(" "), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) JOB_PREFIX = NODE_PREFIX + "job_" + job.id + os.sep
RestoreErrorMode(val) if not os.path.exists(JOB_PREFIX):
os.mkdir(JOB_PREFIX)
headers = {"slave-id":slave_id}
cancelled = False if job.type == netrender.model.JOB_BLENDER:
stdout = bytes() job_path = job.files[0].filepath # path of main file
run_t = time.time() main_path, main_file = os.path.split(job_path)
while process.poll() == None and not cancelled:
stdout += process.stdout.read(32) job_full_path = testFile(conn, job.id, slave_id, 0, JOB_PREFIX, job_path)
current_t = time.time() print("Fullpath", job_full_path)
cancelled = engine.test_break() print("File:", main_file, "and %i other files" % (len(job.files) - 1,))
if current_t - run_t > CANCEL_POLL_SPEED: engine.update_stats("", "Render File "+ main_file+ " for job "+ job.id)
# update logs if needed for rfile in job.files[1:]:
if stdout: print("\t", rfile.filepath)
# (only need to update on one frame, they are linked testFile(conn, job.id, slave_id, rfile.index, JOB_PREFIX, rfile.filepath, main_path)
conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
response = conn.getresponse() # announce log to master
logfile = netrender.model.LogFile(job.id, slave_id, [frame.number for frame in job.frames])
stdout = bytes() conn.request("POST", "/log", bytes(repr(logfile.serialize()), encoding='utf8'))
response = conn.getresponse()
run_t = current_t
if testCancel(conn, job.id, first_frame):
cancelled = True first_frame = job.frames[0].number
# read leftovers if needed # start render
stdout += process.stdout.read() start_t = time.time()
if cancelled: if job.type == netrender.model.JOB_BLENDER:
# kill process if needed frame_args = []
if process.poll() == None:
process.terminate() for frame in job.frames:
continue # to next frame print("frame", frame.number)
frame_args += ["-f", str(frame.number)]
total_t = time.time() - start_t
val = SetErrorMode()
avg_t = total_t / len(job.frames) process = subprocess.Popen([BLENDER_PATH, "-b", "-noaudio", job_full_path, "-o", JOB_PREFIX + "######", "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
RestoreErrorMode(val)
status = process.returncode elif job.type == netrender.model.JOB_PROCESS:
command = job.frames[0].command
print("status", status) val = SetErrorMode()
process = subprocess.Popen(command.split(" "), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# flush the rest of the logs RestoreErrorMode(val)
if stdout:
# (only need to update on one frame, they are linked headers = {"slave-id":slave_id}
conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
if conn.getresponse().status == http.client.NO_CONTENT: cancelled = False
continue stdout = bytes()
run_t = time.time()
headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)} while process.poll() == None and not cancelled:
stdout += process.stdout.read(32)
current_t = time.time()
if status == 0: # non zero status is error cancelled = engine.test_break()
headers["job-result"] = str(DONE) if current_t - run_t > CANCEL_POLL_SPEED:
for frame in job.frames:
headers["job-frame"] = str(frame.number) # update logs if needed
if stdout:
if job.type == netrender.model.JOB_BLENDER: # (only need to update on one frame, they are linked
# send image back to server conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb') response = conn.getresponse()
conn.request("PUT", "/render", f, headers=headers)
f.close() stdout = bytes()
if conn.getresponse().status == http.client.NO_CONTENT:
continue run_t = current_t
elif job.type == netrender.model.JOB_PROCESS: if testCancel(conn, job.id, first_frame):
conn.request("PUT", "/render", headers=headers) cancelled = True
if conn.getresponse().status == http.client.NO_CONTENT:
continue # read leftovers if needed
else: stdout += process.stdout.read()
headers["job-result"] = str(ERROR)
for frame in job.frames: if cancelled:
headers["job-frame"] = str(frame.number) # kill process if needed
# send error result back to server if process.poll() == None:
conn.request("PUT", "/render", headers=headers) process.terminate()
if conn.getresponse().status == http.client.NO_CONTENT: continue # to next frame
continue
else: total_t = time.time() - start_t
if timeout < MAX_TIMEOUT:
timeout += INCREMENT_TIMEOUT avg_t = total_t / len(job.frames)
for i in range(timeout): status = process.returncode
time.sleep(1)
if engine.test_break(): print("status", status)
conn.close()
return # flush the rest of the logs
if stdout:
conn.close() # (only need to update on one frame, they are linked
conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
if conn.getresponse().status == http.client.NO_CONTENT:
continue
headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)}
if status == 0: # non zero status is error
headers["job-result"] = str(DONE)
for frame in job.frames:
headers["job-frame"] = str(frame.number)
if job.type == netrender.model.JOB_BLENDER:
# send image back to server
f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb')
conn.request("PUT", "/render", f, headers=headers)
f.close()
if conn.getresponse().status == http.client.NO_CONTENT:
continue
elif job.type == netrender.model.JOB_PROCESS:
conn.request("PUT", "/render", headers=headers)
if conn.getresponse().status == http.client.NO_CONTENT:
continue
else:
headers["job-result"] = str(ERROR)
for frame in job.frames:
headers["job-frame"] = str(frame.number)
# send error result back to server
conn.request("PUT", "/render", headers=headers)
if conn.getresponse().status == http.client.NO_CONTENT:
continue
else:
if timeout < MAX_TIMEOUT:
timeout += INCREMENT_TIMEOUT
for i in range(timeout):
time.sleep(1)
if engine.test_break():
conn.close()
return
conn.close()
if __name__ == "__main__": if __name__ == "__main__":
pass pass

View File

@@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, # along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@@ -37,318 +37,319 @@ DONE = 2
ERROR = 3 ERROR = 3
class RenderButtonsPanel(bpy.types.Panel): class RenderButtonsPanel(bpy.types.Panel):
bl_space_type = "PROPERTIES" bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW" bl_region_type = "WINDOW"
bl_context = "render" bl_context = "render"
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
def poll(self, context): def poll(self, context):
rd = context.scene.render_data rd = context.scene.render_data
return (rd.use_game_engine==False) and (rd.engine in self.COMPAT_ENGINES) return (rd.use_game_engine==False) and (rd.engine in self.COMPAT_ENGINES)
# Setting panel, use in the scene for now. # Setting panel, use in the scene for now.
@rnaType @rnaType
class RENDER_PT_network_settings(RenderButtonsPanel): class RENDER_PT_network_settings(RenderButtonsPanel):
bl_label = "Network Settings" bl_label = "Network Settings"
COMPAT_ENGINES = {'NET_RENDER'} COMPAT_ENGINES = {'NET_RENDER'}
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
scene = context.scene scene = context.scene
rd = scene.render_data rd = scene.render_data
layout.active = True
split = layout.split()
col = split.column()
layout.active = True
if scene.network_render.mode in ("RENDER_MASTER", "RENDER_SLAVE"):
col.operator("screen.render", text="Start", icon='PLAY').animation = True
col.prop(scene.network_render, "mode") split = layout.split()
col.prop(scene.network_render, "path")
col.prop(scene.network_render, "server_address") col = split.column()
col.prop(scene.network_render, "server_port")
if scene.network_render.mode == "RENDER_MASTER": if scene.network_render.mode in ("RENDER_MASTER", "RENDER_SLAVE"):
col.prop(scene.network_render, "server_broadcast") col.operator("screen.render", text="Start", icon='PLAY').animation = True
else:
col.operator("render.netclientscan", icon='FILE_REFRESH', text="") col.prop(scene.network_render, "mode")
col.prop(scene.network_render, "path")
col.prop(scene.network_render, "server_address")
col.prop(scene.network_render, "server_port")
if scene.network_render.mode == "RENDER_MASTER":
col.prop(scene.network_render, "server_broadcast")
else:
col.operator("render.netclientscan", icon='FILE_REFRESH', text="")
col.operator("render.netclientweb", icon='QUESTION')
@rnaType @rnaType
class RENDER_PT_network_job(RenderButtonsPanel): class RENDER_PT_network_job(RenderButtonsPanel):
bl_label = "Job Settings" bl_label = "Job Settings"
COMPAT_ENGINES = {'NET_RENDER'} COMPAT_ENGINES = {'NET_RENDER'}
def poll(self, context):
scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT")
def draw(self, context): def poll(self, context):
layout = self.layout scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT")
scene = context.scene def draw(self, context):
rd = scene.render_data layout = self.layout
layout.active = True scene = context.scene
rd = scene.render_data
split = layout.split()
layout.active = True
col = split.column()
if scene.network_render.server_address != "[default]": split = layout.split()
col.operator("render.netclientanim", icon='RENDER_ANIMATION')
col.operator("render.netclientsend", icon='FILE_BLEND') col = split.column()
if scene.network_render.job_id: if scene.network_render.server_address != "[default]":
col.operator("screen.render", text="Get Results", icon='RENDER_ANIMATION').animation = True col.operator("render.netclientanim", icon='RENDER_ANIMATION')
col.operator("render.netclientweb", icon='QUESTION') col.operator("render.netclientsend", icon='FILE_BLEND')
col.prop(scene.network_render, "job_name") if scene.network_render.job_id:
col.prop(scene.network_render, "job_category") col.operator("screen.render", text="Get Results", icon='RENDER_ANIMATION').animation = True
row = col.row() col.prop(scene.network_render, "job_name")
row.prop(scene.network_render, "priority") col.prop(scene.network_render, "job_category")
row.prop(scene.network_render, "chunks") row = col.row()
row.prop(scene.network_render, "priority")
row.prop(scene.network_render, "chunks")
@rnaType @rnaType
class RENDER_PT_network_slaves(RenderButtonsPanel): class RENDER_PT_network_slaves(RenderButtonsPanel):
bl_label = "Slaves Status" bl_label = "Slaves Status"
COMPAT_ENGINES = {'NET_RENDER'} COMPAT_ENGINES = {'NET_RENDER'}
def poll(self, context):
scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT"
and scene.network_render.server_address != "[default]")
def draw(self, context): def poll(self, context):
layout = self.layout scene = context.scene
return (super().poll(context)
scene = context.scene and scene.network_render.mode == "RENDER_CLIENT"
netsettings = scene.network_render and scene.network_render.server_address != "[default]")
row = layout.row() def draw(self, context):
row.template_list(netsettings, "slaves", netsettings, "active_slave_index", rows=2) layout = self.layout
sub = row.column(align=True) scene = context.scene
sub.operator("render.netclientslaves", icon='FILE_REFRESH', text="") netsettings = scene.network_render
sub.operator("render.netclientblacklistslave", icon='ZOOMOUT', text="")
if len(netrender.slaves) == 0 and len(netsettings.slaves) > 0:
while(len(netsettings.slaves) > 0):
netsettings.slaves.remove(0)
if netsettings.active_slave_index >= 0 and len(netsettings.slaves) > 0:
layout.separator()
slave = netrender.slaves[netsettings.active_slave_index]
layout.label(text="Name: " + slave.name) row = layout.row()
layout.label(text="Address: " + slave.address[0]) row.template_list(netsettings, "slaves", netsettings, "active_slave_index", rows=2)
layout.label(text="Seen: " + time.ctime(slave.last_seen))
layout.label(text="Stats: " + slave.stats) sub = row.column(align=True)
sub.operator("render.netclientslaves", icon='FILE_REFRESH', text="")
sub.operator("render.netclientblacklistslave", icon='ZOOMOUT', text="")
if len(netrender.slaves) == 0 and len(netsettings.slaves) > 0:
while(len(netsettings.slaves) > 0):
netsettings.slaves.remove(0)
if netsettings.active_slave_index >= 0 and len(netsettings.slaves) > 0:
layout.separator()
slave = netrender.slaves[netsettings.active_slave_index]
layout.label(text="Name: " + slave.name)
layout.label(text="Address: " + slave.address[0])
layout.label(text="Seen: " + time.ctime(slave.last_seen))
layout.label(text="Stats: " + slave.stats)
@rnaType @rnaType
class RENDER_PT_network_slaves_blacklist(RenderButtonsPanel): class RENDER_PT_network_slaves_blacklist(RenderButtonsPanel):
bl_label = "Slaves Blacklist" bl_label = "Slaves Blacklist"
COMPAT_ENGINES = {'NET_RENDER'} COMPAT_ENGINES = {'NET_RENDER'}
def poll(self, context):
scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT"
and scene.network_render.server_address != "[default]")
def draw(self, context):
layout = self.layout
scene = context.scene
netsettings = scene.network_render
row = layout.row() def poll(self, context):
row.template_list(netsettings, "slaves_blacklist", netsettings, "active_blacklisted_slave_index", rows=2) scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT"
and scene.network_render.server_address != "[default]")
sub = row.column(align=True) def draw(self, context):
sub.operator("render.netclientwhitelistslave", icon='ZOOMOUT', text="") layout = self.layout
if len(netrender.blacklist) == 0 and len(netsettings.slaves_blacklist) > 0: scene = context.scene
while(len(netsettings.slaves_blacklist) > 0): netsettings = scene.network_render
netsettings.slaves_blacklist.remove(0)
if netsettings.active_blacklisted_slave_index >= 0 and len(netsettings.slaves_blacklist) > 0:
layout.separator()
slave = netrender.blacklist[netsettings.active_blacklisted_slave_index]
layout.label(text="Name: " + slave.name) row = layout.row()
layout.label(text="Address: " + slave.address[0]) row.template_list(netsettings, "slaves_blacklist", netsettings, "active_blacklisted_slave_index", rows=2)
layout.label(text="Seen: " + time.ctime(slave.last_seen))
layout.label(text="Stats: " + slave.stats) sub = row.column(align=True)
sub.operator("render.netclientwhitelistslave", icon='ZOOMOUT', text="")
if len(netrender.blacklist) == 0 and len(netsettings.slaves_blacklist) > 0:
while(len(netsettings.slaves_blacklist) > 0):
netsettings.slaves_blacklist.remove(0)
if netsettings.active_blacklisted_slave_index >= 0 and len(netsettings.slaves_blacklist) > 0:
layout.separator()
slave = netrender.blacklist[netsettings.active_blacklisted_slave_index]
layout.label(text="Name: " + slave.name)
layout.label(text="Address: " + slave.address[0])
layout.label(text="Seen: " + time.ctime(slave.last_seen))
layout.label(text="Stats: " + slave.stats)
@rnaType @rnaType
class RENDER_PT_network_jobs(RenderButtonsPanel): class RENDER_PT_network_jobs(RenderButtonsPanel):
bl_label = "Jobs" bl_label = "Jobs"
COMPAT_ENGINES = {'NET_RENDER'} COMPAT_ENGINES = {'NET_RENDER'}
def poll(self, context):
scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT"
and scene.network_render.server_address != "[default]")
def draw(self, context):
layout = self.layout
scene = context.scene
netsettings = scene.network_render
row = layout.row() def poll(self, context):
row.template_list(netsettings, "jobs", netsettings, "active_job_index", rows=2) scene = context.scene
return (super().poll(context)
and scene.network_render.mode == "RENDER_CLIENT"
and scene.network_render.server_address != "[default]")
sub = row.column(align=True) def draw(self, context):
sub.operator("render.netclientstatus", icon='FILE_REFRESH', text="") layout = self.layout
sub.operator("render.netclientcancel", icon='ZOOMOUT', text="")
sub.operator("render.netclientcancelall", icon='PANEL_CLOSE', text="")
sub.operator("render.netclientdownload", icon='RENDER_ANIMATION', text="")
if len(netrender.jobs) == 0 and len(netsettings.jobs) > 0: scene = context.scene
while(len(netsettings.jobs) > 0): netsettings = scene.network_render
netsettings.jobs.remove(0)
if netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0:
layout.separator()
job = netrender.jobs[netsettings.active_job_index]
layout.label(text="Name: %s" % job.name) row = layout.row()
layout.label(text="Length: %04i" % len(job)) row.template_list(netsettings, "jobs", netsettings, "active_job_index", rows=2)
layout.label(text="Done: %04i" % job.results[DONE])
layout.label(text="Error: %04i" % job.results[ERROR]) sub = row.column(align=True)
sub.operator("render.netclientstatus", icon='FILE_REFRESH', text="")
sub.operator("render.netclientcancel", icon='ZOOMOUT', text="")
sub.operator("render.netclientcancelall", icon='PANEL_CLOSE', text="")
sub.operator("render.netclientdownload", icon='RENDER_ANIMATION', text="")
if len(netrender.jobs) == 0 and len(netsettings.jobs) > 0:
while(len(netsettings.jobs) > 0):
netsettings.jobs.remove(0)
if netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0:
layout.separator()
job = netrender.jobs[netsettings.active_job_index]
layout.label(text="Name: %s" % job.name)
layout.label(text="Length: %04i" % len(job))
layout.label(text="Done: %04i" % job.results[DONE])
layout.label(text="Error: %04i" % job.results[ERROR])
@rnaType @rnaType
class NetRenderSettings(bpy.types.IDPropertyGroup): class NetRenderSettings(bpy.types.IDPropertyGroup):
pass pass
@rnaType @rnaType
class NetRenderSlave(bpy.types.IDPropertyGroup): class NetRenderSlave(bpy.types.IDPropertyGroup):
pass pass
@rnaType @rnaType
class NetRenderJob(bpy.types.IDPropertyGroup): class NetRenderJob(bpy.types.IDPropertyGroup):
pass pass
bpy.types.Scene.PointerProperty(attr="network_render", type=NetRenderSettings, name="Network Render", description="Network Render Settings") bpy.types.Scene.PointerProperty(attr="network_render", type=NetRenderSettings, name="Network Render", description="Network Render Settings")
NetRenderSettings.StringProperty( attr="server_address", NetRenderSettings.StringProperty( attr="server_address",
name="Server address", name="Server address",
description="IP or name of the master render server", description="IP or name of the master render server",
maxlen = 128, maxlen = 128,
default = "[default]") default = "[default]")
NetRenderSettings.IntProperty( attr="server_port", NetRenderSettings.IntProperty( attr="server_port",
name="Server port", name="Server port",
description="port of the master render server", description="port of the master render server",
default = 8000, default = 8000,
min=1, min=1,
max=65535) max=65535)
NetRenderSettings.BoolProperty( attr="server_broadcast", NetRenderSettings.BoolProperty( attr="server_broadcast",
name="Broadcast server address", name="Broadcast server address",
description="broadcast server address on local network", description="broadcast server address on local network",
default = True) default = True)
default_path = os.environ.get("TEMP", None) default_path = os.environ.get("TEMP", None)
if not default_path: if not default_path:
if os.name == 'nt': if os.name == 'nt':
default_path = "c:/tmp/" default_path = "c:/tmp/"
else: else:
default_path = "/tmp/" default_path = "/tmp/"
elif not default_path.endswith(os.sep): elif not default_path.endswith(os.sep):
default_path += os.sep default_path += os.sep
NetRenderSettings.StringProperty( attr="path", NetRenderSettings.StringProperty( attr="path",
name="Path", name="Path",
description="Path for temporary files", description="Path for temporary files",
maxlen = 128, maxlen = 128,
default = default_path) default = default_path)
NetRenderSettings.StringProperty( attr="job_name", NetRenderSettings.StringProperty( attr="job_name",
name="Job name", name="Job name",
description="Name of the job", description="Name of the job",
maxlen = 128, maxlen = 128,
default = "[default]") default = "[default]")
NetRenderSettings.StringProperty( attr="job_category", NetRenderSettings.StringProperty( attr="job_category",
name="Job category", name="Job category",
description="Category of the job", description="Category of the job",
maxlen = 128, maxlen = 128,
default = "") default = "")
NetRenderSettings.IntProperty( attr="chunks", NetRenderSettings.IntProperty( attr="chunks",
name="Chunks", name="Chunks",
description="Number of frame to dispatch to each slave in one chunk", description="Number of frame to dispatch to each slave in one chunk",
default = 5, default = 5,
min=1, min=1,
max=65535) max=65535)
NetRenderSettings.IntProperty( attr="priority", NetRenderSettings.IntProperty( attr="priority",
name="Priority", name="Priority",
description="Priority of the job", description="Priority of the job",
default = 1, default = 1,
min=1, min=1,
max=10) max=10)
NetRenderSettings.StringProperty( attr="job_id", NetRenderSettings.StringProperty( attr="job_id",
name="Network job id", name="Network job id",
description="id of the last sent render job", description="id of the last sent render job",
maxlen = 64, maxlen = 64,
default = "") default = "")
NetRenderSettings.IntProperty( attr="active_slave_index", NetRenderSettings.IntProperty( attr="active_slave_index",
name="Index of the active slave", name="Index of the active slave",
description="", description="",
default = -1, default = -1,
min= -1, min= -1,
max=65535) max=65535)
NetRenderSettings.IntProperty( attr="active_blacklisted_slave_index", NetRenderSettings.IntProperty( attr="active_blacklisted_slave_index",
name="Index of the active slave", name="Index of the active slave",
description="", description="",
default = -1, default = -1,
min= -1, min= -1,
max=65535) max=65535)
NetRenderSettings.IntProperty( attr="active_job_index", NetRenderSettings.IntProperty( attr="active_job_index",
name="Index of the active job", name="Index of the active job",
description="", description="",
default = -1, default = -1,
min= -1, min= -1,
max=65535) max=65535)
NetRenderSettings.EnumProperty(attr="mode", NetRenderSettings.EnumProperty(attr="mode",
items=( items=(
("RENDER_CLIENT", "Client", "Act as render client"), ("RENDER_CLIENT", "Client", "Act as render client"),
("RENDER_MASTER", "Master", "Act as render master"), ("RENDER_MASTER", "Master", "Act as render master"),
("RENDER_SLAVE", "Slave", "Act as render slave"), ("RENDER_SLAVE", "Slave", "Act as render slave"),
), ),
name="Network mode", name="Network mode",
description="Mode of operation of this instance", description="Mode of operation of this instance",
default="RENDER_CLIENT") default="RENDER_CLIENT")
NetRenderSettings.CollectionProperty(attr="slaves", type=NetRenderSlave, name="Slaves", description="") NetRenderSettings.CollectionProperty(attr="slaves", type=NetRenderSlave, name="Slaves", description="")
NetRenderSettings.CollectionProperty(attr="slaves_blacklist", type=NetRenderSlave, name="Slaves Blacklist", description="") NetRenderSettings.CollectionProperty(attr="slaves_blacklist", type=NetRenderSlave, name="Slaves Blacklist", description="")
NetRenderSettings.CollectionProperty(attr="jobs", type=NetRenderJob, name="Job List", description="") NetRenderSettings.CollectionProperty(attr="jobs", type=NetRenderJob, name="Job List", description="")
NetRenderSlave.StringProperty( attr="name", NetRenderSlave.StringProperty( attr="name",
name="Name of the slave", name="Name of the slave",
description="", description="",
maxlen = 64, maxlen = 64,
default = "") default = "")
NetRenderJob.StringProperty( attr="name", NetRenderJob.StringProperty( attr="name",
name="Name of the job", name="Name of the job",
description="", description="",
maxlen = 128, maxlen = 128,
default = "") default = "")

View File

@@ -4,12 +4,12 @@
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, # along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@@ -51,26 +51,22 @@ DONE = 2
ERROR = 3 ERROR = 3
FRAME_STATUS_TEXT = { FRAME_STATUS_TEXT = {
QUEUED: "Queued", QUEUED: "Queued",
DISPATCHED: "Dispatched", DISPATCHED: "Dispatched",
DONE: "Done", DONE: "Done",
ERROR: "Error" ERROR: "Error"
} }
def rnaType(rna_type): def rnaType(rna_type):
if bpy: bpy.types.register(rna_type) if bpy: bpy.types.register(rna_type)
return rna_type return rna_type
def rnaOperator(rna_op):
if bpy: bpy.ops.add(rna_op)
return rna_op
def reporting(report, message, errorType = None): def reporting(report, message, errorType = None):
if errorType: if errorType:
t = 'ERROR' t = 'ERROR'
else: else:
t = 'INFO' t = 'INFO'
if report: if report:
report(t, message) report(t, message)
return None return None
@@ -86,14 +82,14 @@ def clientScan(report = None):
s.settimeout(30) s.settimeout(30)
s.bind(('', 8000)) s.bind(('', 8000))
buf, address = s.recvfrom(64) buf, address = s.recvfrom(64)
address = address[0] address = address[0]
port = int(str(buf, encoding='utf8')) port = int(str(buf, encoding='utf8'))
reporting(report, "Master server found") reporting(report, "Master server found")
return (address, port) return (address, port)
except socket.timeout: except socket.timeout:
reporting(report, "No master server on network", IOError) reporting(report, "No master server on network", IOError)
@@ -109,10 +105,10 @@ def clientConnection(address, port, report = None):
address, port = clientScan() address, port = clientScan()
if address == "": if address == "":
return None return None
try: try:
conn = http.client.HTTPConnection(address, port) conn = http.client.HTTPConnection(address, port)
if conn: if conn:
if clientVerifyVersion(conn): if clientVerifyVersion(conn):
return conn return conn
@@ -127,21 +123,21 @@ def clientConnection(address, port, report = None):
raise raise
def clientVerifyVersion(conn): def clientVerifyVersion(conn):
conn.request("GET", "/version") conn.request("GET", "/version")
response = conn.getresponse() response = conn.getresponse()
if response.status != http.client.OK: if response.status != http.client.OK:
conn.close() conn.close()
return False return False
server_version = response.read() server_version = response.read()
if server_version != VERSION: if server_version != VERSION:
print("Incorrect server version!") print("Incorrect server version!")
print("expected", str(VERSION, encoding='utf8'), "received", str(server_version, encoding='utf8')) print("expected", str(VERSION, encoding='utf8'), "received", str(server_version, encoding='utf8'))
return False return False
return True return True
def fileURL(job_id, file_index): def fileURL(job_id, file_index):
return "/file_%s_%i" % (job_id, file_index) return "/file_%s_%i" % (job_id, file_index)
@@ -156,20 +152,20 @@ def cancelURL(job_id):
return "/cancel_%s" % (job_id) return "/cancel_%s" % (job_id)
def prefixPath(prefix_directory, file_path, prefix_path): def prefixPath(prefix_directory, file_path, prefix_path):
if os.path.isabs(file_path): if os.path.isabs(file_path):
# if an absolute path, make sure path exists, if it doesn't, use relative local path # if an absolute path, make sure path exists, if it doesn't, use relative local path
full_path = file_path full_path = file_path
if not os.path.exists(full_path): if not os.path.exists(full_path):
p, n = os.path.split(full_path) p, n = os.path.split(full_path)
if prefix_path and p.startswith(prefix_path): if prefix_path and p.startswith(prefix_path):
directory = prefix_directory + p[len(prefix_path):] directory = prefix_directory + p[len(prefix_path):]
full_path = directory + os.sep + n full_path = directory + os.sep + n
if not os.path.exists(directory): if not os.path.exists(directory):
os.mkdir(directory) os.mkdir(directory)
else: else:
full_path = prefix_directory + n full_path = prefix_directory + n
else: else:
full_path = prefix_directory + file_path full_path = prefix_directory + file_path
return full_path return full_path

View File

@@ -85,7 +85,6 @@ def _main():
# a bit nasty but this prevents help() and input() from locking blender # a bit nasty but this prevents help() and input() from locking blender
# Ideally we could have some way for the console to replace sys.stdin but # Ideally we could have some way for the console to replace sys.stdin but
# python would lock blender while waiting for a return value, not easy :| # python would lock blender while waiting for a return value, not easy :|
import sys
sys.stdin = None sys.stdin = None
# if "-d" in sys.argv: # Enable this to measure startup speed # if "-d" in sys.argv: # Enable this to measure startup speed
@@ -100,4 +99,10 @@ def _main():
else: else:
load_scripts() load_scripts()
# constants
version = _bpy._VERSION
version_string = _bpy._VERSION_STR
home = _bpy._HOME
_main() _main()

View File

@@ -21,7 +21,7 @@
# for slightly faster access # for slightly faster access
from _bpy import ops as ops_module from _bpy import ops as ops_module
op_add = ops_module.add # op_add = ops_module.add
op_remove = ops_module.remove op_remove = ops_module.remove
op_add_macro = ops_module.add_macro op_add_macro = ops_module.add_macro
op_dir = ops_module.dir op_dir = ops_module.dir

View File

@@ -42,25 +42,27 @@ class Object(bpy_types.ID):
@property @property
def children(self): def children(self):
"""All the children of this object"""
import bpy import bpy
return [child for child in bpy.data.objects if child.parent == self] return [child for child in bpy.data.objects if child.parent == self]
class _GenericBone: class _GenericBone:
''' """
functions for bones, common between Armature/Pose/Edit bones. functions for bones, common between Armature/Pose/Edit bones.
internal subclassing use only. internal subclassing use only.
''' """
__slots__ = () __slots__ = ()
def translate(self, vec): def translate(self, vec):
"""Utility function to add *vec* to the head and tail of this bone."""
self.head += vec self.head += vec
self.tail += vec self.tail += vec
def parent_index(self, parent_test): def parent_index(self, parent_test):
''' """
The same as 'bone in other_bone.parent_recursive' but saved generating a list. The same as 'bone in other_bone.parent_recursive' but saved generating a list.
''' """
# use the name so different types can be tested. # use the name so different types can be tested.
name = parent_test.name name = parent_test.name
@@ -76,11 +78,13 @@ class _GenericBone:
@property @property
def basename(self): def basename(self):
"""The name of this bone before any '.' character"""
#return self.name.rsplit(".", 1)[0] #return self.name.rsplit(".", 1)[0]
return self.name.split(".")[0] return self.name.split(".")[0]
@property @property
def parent_recursive(self): def parent_recursive(self):
"""A list of parents, starting with the immediate parent"""
parent_list = [] parent_list = []
parent = self.parent parent = self.parent
@@ -94,23 +98,26 @@ class _GenericBone:
@property @property
def length(self): def length(self):
"""The distance from head to tail, when set the head is moved to fit the length."""
return self.vector.length return self.vector.length
@length.setter @length.setter
def length(self, value): def length(self, value):
"""The distance from head to tail"""
self.tail = self.head + ((self.tail - self.head).normalize() * value) self.tail = self.head + ((self.tail - self.head).normalize() * value)
@property @property
def vector(self): def vector(self):
"""The direction this bone is pointing. Utility function for (tail - head)"""
return (self.tail - self.head) return (self.tail - self.head)
@property @property
def children(self): def children(self):
"""A list of all the bones children."""
return [child for child in self._other_bones if child.parent == self] return [child for child in self._other_bones if child.parent == self]
@property @property
def children_recursive(self): def children_recursive(self):
"""a list of all children from this bone."""
bones_children = [] bones_children = []
for bone in self._other_bones: for bone in self._other_bones:
index = bone.parent_index(self) index = bone.parent_index(self)
@@ -123,10 +130,11 @@ class _GenericBone:
@property @property
def children_recursive_basename(self): def children_recursive_basename(self):
''' """
Returns a chain of children with the same base name as this bone Returns a chain of children with the same base name as this bone
Only direct chains are supported, forks caused by multiple children with matching basenames will. Only direct chains are supported, forks caused by multiple children with matching basenames will
''' terminate the function and not be returned.
"""
basename = self.basename basename = self.basename
chain = [] chain = []
@@ -177,10 +185,10 @@ class EditBone(StructRNA, _GenericBone):
__slots__ = () __slots__ = ()
def align_orientation(self, other): def align_orientation(self, other):
''' """
Align this bone to another by moving its tail and settings its roll Align this bone to another by moving its tail and settings its roll
the length of the other bone is not used. the length of the other bone is not used.
''' """
vec = other.vector.normalize() * self.length vec = other.vector.normalize() * self.length
self.tail = self.head + vec self.tail = self.head + vec
self.roll = other.roll self.roll = other.roll
@@ -196,10 +204,10 @@ class Mesh(bpy_types.ID):
__slots__ = () __slots__ = ()
def from_pydata(self, verts, edges, faces): def from_pydata(self, verts, edges, faces):
''' """
Make a mesh from a list of verts/edges/faces Make a mesh from a list of verts/edges/faces
Until we have a nicer way to make geometry, use this. Until we have a nicer way to make geometry, use this.
''' """
self.add_geometry(len(verts), len(edges), len(faces)) self.add_geometry(len(verts), len(edges), len(faces))
verts_flat = [f for v in verts for f in v] verts_flat = [f for v in verts for f in v]
@@ -244,7 +252,7 @@ class Mesh(bpy_types.ID):
return [edge_face_count_dict.get(ed.key, 0) for ed in mesh.edges] return [edge_face_count_dict.get(ed.key, 0) for ed in mesh.edges]
def edge_loops(self, faces=None, seams=()): def edge_loops(self, faces=None, seams=()):
''' """
Edge loops defined by faces Edge loops defined by faces
Takes me.faces or a list of faces and returns the edge loops Takes me.faces or a list of faces and returns the edge loops
@@ -255,12 +263,12 @@ class Mesh(bpy_types.ID):
[ [(0,1), (4, 8), (3,8)], ...] [ [(0,1), (4, 8), (3,8)], ...]
optionaly, seams are edge keys that will be removed optionaly, seams are edge keys that will be removed
''' """
OTHER_INDEX = 2,3,0,1 # opposite face index OTHER_INDEX = 2, 3, 0, 1 # opposite face index
if faces is None: if faces is None:
faces= self.faces faces = self.faces
edges = {} edges = {}
@@ -278,7 +286,7 @@ class Mesh(bpy_types.ID):
edge_loops = [] edge_loops = []
for edkey, ed_adj in edges.items(): for edkey, ed_adj in edges.items():
if 0 <len(ed_adj) < 3: # 1 or 2 if 0 < len(ed_adj) < 3: # 1 or 2
# Seek the first edge # Seek the first edge
context_loop = [edkey, ed_adj[0]] context_loop = [edkey, ed_adj[0]]
edge_loops.append(context_loop) edge_loops.append(context_loop)
@@ -296,7 +304,7 @@ class Mesh(bpy_types.ID):
ed_adj = edges[context_loop[-1]] ed_adj = edges[context_loop[-1]]
if len(ed_adj) != 2: if len(ed_adj) != 2:
if other_dir and flipped==False: # the original edge had 2 other edges if other_dir and flipped == False: # the original edge had 2 other edges
flipped = True # only flip the list once flipped = True # only flip the list once
context_loop.reverse() context_loop.reverse()
ed_adj[:] = [] ed_adj[:] = []
@@ -311,7 +319,7 @@ class Mesh(bpy_types.ID):
break break
i = ed_adj.index(context_loop[-2]) i = ed_adj.index(context_loop[-2])
context_loop.append( ed_adj[ not i] ) context_loop.append(ed_adj[not i])
# Dont look at this again # Dont look at this again
ed_adj[:] = [] ed_adj[:] = []
@@ -372,6 +380,33 @@ class Macro(StructRNA, metaclass=OrderedMeta):
class Menu(StructRNA): class Menu(StructRNA):
__slots__ = () __slots__ = ()
@classmethod
def _dyn_menu_initialize(cls):
draw_funcs = getattr(cls.draw, "_draw_funcs", None)
if draw_funcs is None:
def draw_ls(*args):
for func in draw_ls._draw_funcs:
func(*args)
draw_funcs = draw_ls._draw_funcs = [cls.draw]
cls.draw = draw_ls
return draw_funcs
@classmethod
def append(cls, draw_func):
"""Prepend an draw function to this menu, takes the same arguments as the menus draw function."""
draw_funcs = cls._dyn_menu_initialize()
draw_funcs.append(draw_func)
@classmethod
def prepend(cls, draw_func):
"""Prepend a draw function to this menu, takes the same arguments as the menus draw function."""
draw_funcs = cls._dyn_menu_initialize()
draw_funcs.insert(0, draw_func)
def path_menu(self, searchpaths, operator): def path_menu(self, searchpaths, operator):
layout = self.layout layout = self.layout
# hard coded to set the operators 'path' to the filename. # hard coded to set the operators 'path' to the filename.
@@ -396,9 +431,9 @@ class Menu(StructRNA):
layout.operator(operator, text=bpy.utils.display_name(f)).path = path layout.operator(operator, text=bpy.utils.display_name(f)).path = path
def draw_preset(self, context): def draw_preset(self, context):
'''Define these on the subclass """Define these on the subclass
- preset_operator - preset_operator
- preset_subdir - preset_subdir
''' """
import bpy import bpy
self.path_menu(bpy.utils.preset_paths(self.preset_subdir), self.preset_operator) self.path_menu(bpy.utils.preset_paths(self.preset_subdir), self.preset_operator)

View File

@@ -1,118 +0,0 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
import bpy
def collect_baseclasses(_class, bases):
if _class is type or _class is object:
return bases
bases.append(_class)
for _superclass in _class.__bases__:
collect_baseclasses(_superclass, bases)
return bases
def collect_subclasses(_class, subs):
if _class is type or _class is object:
return subs
subs.append(_class)
for _subclass in _class.__subclasses__():
collect_subclasses(_subclass, subs)
return subs
class DynMenu(bpy.types.Menu):
def draw(self, context):
'''
This is a draw function that is used to call all subclasses draw functions
starting from the registered classes draw function and working down.
DynMenu.setup() must be called first.
Sort/group classes could be nice
'''
subclass_ls = []
collect_subclasses(self.__class__, subclass_ls)
# print(subclass_ls)
for subclass in subclass_ls:
# print("drawwing", subclass) # , dir(subclass))
subclass.internal_draw(self, context)
# print("subclass.internal_draw", subclass.internal_draw)
def setup(menu_class):
'''
Setup subclasses (not needed when self.add() is used)
'''
bases = collect_baseclasses(menu_class, [])
# Incase 'DynMenu' isnt last
while bases[-1] is not DynMenu:
bases.pop()
bases.pop() # remove 'DynMenu'
root_class = bases[-1] # this is the registered class
for subclass in collect_subclasses(root_class, []):
#print(subclass)
draw = getattr(subclass, 'draw', None)
if draw and not hasattr(subclass, 'internal_draw'):
# print("replace", subclass, draw)
try:
del subclass.draw
except:
pass
subclass.internal_draw = draw
root_class.draw = DynMenu.draw
def add(menu_class, func):
'''
Add a single function directly without having to make a class
important that the returned value should be stored in the module that called it.
'''
newclass = type('<menuclass>', (menu_class,), {})
newclass.internal_draw = func
setup(menu_class)
return newclass
'''
# so we dont need to import this module
DynMenu.setup = setup
DynMenu.add = add
# Only so we can access as bpy.types.
# dont ever use this directly!
bpy.types.register(DynMenu)
'''

View File

@@ -19,9 +19,8 @@
# <pep8 compliant> # <pep8 compliant>
import bpy import bpy
from rigify import RigifyError, get_layer_dict from rigify import RigifyError
from rigify_utils import bone_class_instance, copy_bone_simple, blend_bone_list, get_side_name, get_base_name, add_pole_target_bone from rigify_utils import bone_class_instance, copy_bone_simple, add_pole_target_bone
from rna_prop_ui import rna_idprop_ui_prop_get
from Mathutils import Vector from Mathutils import Vector
METARIG_NAMES = "hips", "thigh", "shin", "foot", "toe" METARIG_NAMES = "hips", "thigh", "shin", "foot", "toe"

View File

@@ -90,6 +90,7 @@ def metarig_template():
pbone = obj.pose.bones['rib_cage'] pbone = obj.pose.bones['rib_cage']
pbone['type'] = 'spine_pivot_flex' pbone['type'] = 'spine_pivot_flex'
def metarig_definition(obj, orig_bone_name): def metarig_definition(obj, orig_bone_name):
''' '''
The bone given is the second in a chain. The bone given is the second in a chain.

View File

@@ -16,13 +16,37 @@
# #
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
# classes for extracting info from blenders internal classes # classes for extracting info from blenders internal classes
import bpy import bpy
# use to strip python paths
script_paths = bpy.utils.script_paths()
def range_str(val):
if val < -10000000:
return '-inf'
elif val > 10000000:
return 'inf'
elif type(val) == float:
return '%g' % val
else:
return str(val)
def float_as_string(f):
val_str = "%g" % f
if '.' not in val_str and '-' not in val_str: # value could be 1e-05
val_str += '.0'
return val_str
class InfoStructRNA: class InfoStructRNA:
global_lookup = {} global_lookup = {}
def __init__(self, rna_type): def __init__(self, rna_type):
self.bl_rna = rna_type self.bl_rna = rna_type
@@ -43,18 +67,53 @@ class InfoStructRNA:
def build(self): def build(self):
rna_type = self.bl_rna rna_type = self.bl_rna
parent_id = self.identifier parent_id = self.identifier
self.properties[:] = [GetInfoPropertyRNA(rna_prop, parent_id) for rna_prop in rna_type.properties.values()] self.properties[:] = [GetInfoPropertyRNA(rna_prop, parent_id) for rna_id, rna_prop in rna_type.properties.items() if rna_id != "rna_type"]
self.functions[:] = [GetInfoFunctionRNA(rna_prop, parent_id) for rna_prop in rna_type.functions.values()] self.functions[:] = [GetInfoFunctionRNA(rna_prop, parent_id) for rna_prop in rna_type.functions.values()]
def getNestedProperties(self, ls = None): def get_bases(self):
bases = []
item = self
while item:
item = item.base
if item:
bases.append(item)
return bases
def get_nested_properties(self, ls=None):
if not ls: if not ls:
ls = self.properties[:] ls = self.properties[:]
if self.nested: if self.nested:
self.nested.getNestedProperties(ls) self.nested.get_nested_properties(ls)
return ls return ls
def _get_py_visible_attrs(self):
attrs = []
py_class = getattr(bpy.types, self.identifier)
for attr_str in dir(py_class):
if attr_str.startswith("_"):
continue
attrs.append((attr_str, getattr(py_class, attr_str)))
return attrs
def get_py_properties(self):
properties = []
for identifier, attr in self._get_py_visible_attrs():
if type(attr) is property:
properties.append((identifier, attr))
return properties
def get_py_functions(self):
import types
functions = []
for identifier, attr in self._get_py_visible_attrs():
if type(attr) in (types.FunctionType, types.MethodType):
functions.append((identifier, attr))
return functions
def __repr__(self): def __repr__(self):
txt = '' txt = ''
@@ -74,44 +133,137 @@ class InfoStructRNA:
class InfoPropertyRNA: class InfoPropertyRNA:
global_lookup = {} global_lookup = {}
def __init__(self, rna_prop): def __init__(self, rna_prop):
self.bl_prop = rna_prop self.bl_prop = rna_prop
self.identifier = rna_prop.identifier self.identifier = rna_prop.identifier
self.name = rna_prop.name self.name = rna_prop.name
self.description = rna_prop.description.strip() self.description = rna_prop.description.strip()
self.default_str = "<UNKNOWN>"
def build(self): def build(self):
rna_prop = self.bl_prop rna_prop = self.bl_prop
self.enum_items = [] self.enum_items = []
self.min = -1 self.min = getattr(rna_prop, "hard_min", -1)
self.max = -1 self.max = getattr(rna_prop, "hard_max", -1)
self.array_length = getattr(rna_prop, "array_length", 0) self.array_length = getattr(rna_prop, "array_length", 0)
self.collection_type = GetInfoStructRNA(rna_prop.srna)
self.is_required = rna_prop.is_required
self.is_readonly = rna_prop.is_readonly
self.is_never_none = rna_prop.is_never_none
self.type = rna_prop.type.lower() self.type = rna_prop.type.lower()
self.fixed_type = GetInfoStructRNA(rna_prop.fixed_type) # valid for pointer/collections fixed_type = getattr(rna_prop, "fixed_type", "")
if fixed_type:
self.fixed_type = GetInfoStructRNA(fixed_type) # valid for pointer/collections
else:
self.fixed_type = None
if self.type == "enum":
self.enum_items[:] = rna_prop.items.keys()
if self.array_length:
self.default = tuple(getattr(rna_prop, "default_array", ()))
self.default_str = ''
# special case for floats
if len(self.default) > 0:
if type(self.default[0]) is float:
self.default_str = "(%s)" % ", ".join([float_as_string(f) for f in self.default])
if not self.default_str:
self.default_str = str(self.default)
else:
self.default = getattr(rna_prop, "default", "")
if type(self.default) is float:
self.default_str = float_as_string(self.default)
else:
self.default_str = str(self.default)
self.srna = GetInfoStructRNA(rna_prop.srna) # valid for pointer/collections self.srna = GetInfoStructRNA(rna_prop.srna) # valid for pointer/collections
def get_default_string(self):
# pointer has no default, just set as None
if self.type == "pointer":
return "None"
elif self.type == "string":
return '"' + self.default_str + '"'
elif self.type == "enum":
if self.default_str:
return "'" + self.default_str + "'"
else:
return ""
return self.default_str
def get_arg_default(self, force=True):
default = self.get_default_string()
if default and (force or self.is_required == False):
return "%s=%s" % (self.identifier, default)
return self.identifier
def get_type_description(self, as_arg=False, class_fmt="%s"):
type_str = ""
if self.fixed_type is None:
type_str += self.type
if self.array_length:
type_str += " array of %d items" % (self.array_length)
if self.type in ("float", "int"):
type_str += " in [%s, %s]" % (range_str(self.min), range_str(self.max))
elif self.type == "enum":
type_str += " in [%s]" % ', '.join([("'%s'" % s) for s in self.enum_items])
else:
if self.type == "collection":
if self.collection_type:
collection_str = (class_fmt % self.collection_type.identifier) + " collection of "
else:
collection_str = "Collection of "
else:
collection_str = ""
type_str += collection_str + (class_fmt % self.fixed_type.identifier)
if as_arg:
if not self.is_required:
type_str += ", (optional)"
else: # readonly is only useful for selfs, not args
if self.is_readonly:
type_str += ", (readonly)"
if self.is_never_none:
type_str += ", (never None)"
return type_str
def __repr__(self): def __repr__(self):
txt = '' txt = ''
txt += ' * ' + self.identifier + ': ' + self.description txt += ' * ' + self.identifier + ': ' + self.description
return txt return txt
class InfoFunctionRNA: class InfoFunctionRNA:
global_lookup = {} global_lookup = {}
def __init__(self, rna_func): def __init__(self, rna_func):
self.bl_func = rna_func self.bl_func = rna_func
self.identifier = rna_func.identifier self.identifier = rna_func.identifier
# self.name = rna_func.name # functions have no name! # self.name = rna_func.name # functions have no name!
self.description = rna_func.description.strip() self.description = rna_func.description.strip()
self.args = [] # todo self.args = []
self.return_value = None # todo self.return_value = None
def build(self): def build(self):
rna_prop = self.bl_prop rna_func = self.bl_func
pass parent_id = rna_func
for rna_prop in rna_func.parameters.values():
prop = GetInfoPropertyRNA(rna_prop, parent_id)
if rna_prop.use_return:
self.return_value = prop
else:
self.args.append(prop)
def __repr__(self): def __repr__(self):
txt = '' txt = ''
@@ -123,6 +275,56 @@ class InfoFunctionRNA:
return txt return txt
class InfoOperatorRNA:
global_lookup = {}
def __init__(self, rna_op):
self.bl_op = rna_op
self.identifier = rna_op.identifier
mod, name = self.identifier.split("_OT_", 1)
self.module_name = mod.lower()
self.func_name = name
# self.name = rna_func.name # functions have no name!
self.description = rna_op.description.strip()
self.args = []
def build(self):
rna_op = self.bl_op
parent_id = self.identifier
for rna_id, rna_prop in rna_op.properties.items():
if rna_id == "rna_type":
continue
prop = GetInfoPropertyRNA(rna_prop, parent_id)
self.args.append(prop)
def get_location(self):
op_class = getattr(bpy.types, self.identifier)
op_func = getattr(op_class, "execute", None)
if op_func is None:
op_func = getattr(op_class, "invoke", None)
if op_func is None:
op_func = getattr(op_class, "poll", None)
if op_func:
op_code = op_func.__code__
source_path = op_code.co_filename
# clear the prefix
for p in script_paths:
source_path = source_path.split(p)[-1]
if source_path[0] in "/\\":
source_path = source_path[1:]
return source_path, op_code.co_firstlineno
else:
return None, None
def _GetInfoRNA(bl_rna, cls, parent_id=''): def _GetInfoRNA(bl_rna, cls, parent_id=''):
if bl_rna == None: if bl_rna == None:
@@ -139,21 +341,27 @@ def _GetInfoRNA(bl_rna, cls, parent_id=''):
def GetInfoStructRNA(bl_rna): def GetInfoStructRNA(bl_rna):
return _GetInfoRNA(bl_rna, InfoStructRNA) return _GetInfoRNA(bl_rna, InfoStructRNA)
def GetInfoPropertyRNA(bl_rna, parent_id): def GetInfoPropertyRNA(bl_rna, parent_id):
return _GetInfoRNA(bl_rna, InfoPropertyRNA, parent_id) return _GetInfoRNA(bl_rna, InfoPropertyRNA, parent_id)
def GetInfoFunctionRNA(bl_rna, parent_id): def GetInfoFunctionRNA(bl_rna, parent_id):
return _GetInfoRNA(bl_rna, InfoFunctionRNA, parent_id) return _GetInfoRNA(bl_rna, InfoFunctionRNA, parent_id)
def GetInfoOperatorRNA(bl_rna):
return _GetInfoRNA(bl_rna, InfoOperatorRNA)
def BuildRNAInfo(): def BuildRNAInfo():
# Use for faster lookups # Use for faster lookups
# use rna_struct.identifier as the key for each dict # use rna_struct.identifier as the key for each dict
rna_struct_dict = {} # store identifier:rna lookups rna_struct_dict = {} # store identifier:rna lookups
rna_full_path_dict = {} # store the result of full_rna_struct_path(rna_struct) rna_full_path_dict = {} # store the result of full_rna_struct_path(rna_struct)
rna_children_dict = {} # store all rna_structs nested from here rna_children_dict = {} # store all rna_structs nested from here
rna_references_dict = {} # store a list of rna path strings that reference this type rna_references_dict = {} # store a list of rna path strings that reference this type
rna_functions_dict = {} # store all functions directly in this type (not inherited) rna_functions_dict = {} # store all functions directly in this type (not inherited)
rna_words = set() rna_words = set()
def rna_id_ignore(rna_id): def rna_id_ignore(rna_id):
@@ -166,7 +374,8 @@ def BuildRNAInfo():
return True return True
if "_PT_" in rna_id: if "_PT_" in rna_id:
return True return True
if "_HT_" in rna_id:
return True
return False return False
def full_rna_struct_path(rna_struct): def full_rna_struct_path(rna_struct):
@@ -181,8 +390,10 @@ def BuildRNAInfo():
# def write_func(rna_func, ident): # def write_func(rna_func, ident):
def base_id(rna_struct): def base_id(rna_struct):
try: return rna_struct.base.identifier try:
except: return '' # invalid id return rna_struct.base.identifier
except:
return "" # invalid id
#structs = [(base_id(rna_struct), rna_struct.identifier, rna_struct) for rna_struct in bpy.doc.structs.values()] #structs = [(base_id(rna_struct), rna_struct.identifier, rna_struct) for rna_struct in bpy.doc.structs.values()]
''' '''
@@ -194,8 +405,7 @@ def BuildRNAInfo():
for rna_type_name in dir(bpy.types): for rna_type_name in dir(bpy.types):
rna_type = getattr(bpy.types, rna_type_name) rna_type = getattr(bpy.types, rna_type_name)
try: rna_struct = rna_type.bl_rna rna_struct = getattr(rna_type, "bl_rna", None)
except: rna_struct = None
if rna_struct: if rna_struct:
#if not rna_type_name.startswith('__'): #if not rna_type_name.startswith('__'):
@@ -203,7 +413,7 @@ def BuildRNAInfo():
identifier = rna_struct.identifier identifier = rna_struct.identifier
if not rna_id_ignore(identifier): if not rna_id_ignore(identifier):
structs.append( (base_id(rna_struct), identifier, rna_struct) ) structs.append((base_id(rna_struct), identifier, rna_struct))
# Simple lookup # Simple lookup
rna_struct_dict[identifier] = rna_struct rna_struct_dict[identifier] = rna_struct
@@ -212,12 +422,12 @@ def BuildRNAInfo():
rna_full_path_dict[identifier] = full_rna_struct_path(rna_struct) rna_full_path_dict[identifier] = full_rna_struct_path(rna_struct)
# Store a list of functions, remove inherited later # Store a list of functions, remove inherited later
rna_functions_dict[identifier]= list(rna_struct.functions) rna_functions_dict[identifier] = list(rna_struct.functions)
# fill in these later # fill in these later
rna_children_dict[identifier]= [] rna_children_dict[identifier] = []
rna_references_dict[identifier]= [] rna_references_dict[identifier] = []
else: else:
@@ -247,11 +457,11 @@ def BuildRNAInfo():
data = structs.pop(i) data = structs.pop(i)
ok = False ok = False
while i < len(structs): while i < len(structs):
if structs[i][1]==rna_base: if structs[i][1] == rna_base:
structs.insert(i+1, data) # insert after the item we depend on. structs.insert(i + 1, data) # insert after the item we depend on.
ok = True ok = True
break break
i+=1 i += 1
if not ok: if not ok:
print('Dependancy "%s" could not be found for "%s"' % (identifier, rna_base)) print('Dependancy "%s" could not be found for "%s"' % (identifier, rna_base))
@@ -269,37 +479,40 @@ def BuildRNAInfo():
rna_base_func_keys = [f.identifier for f in rna_struct_dict[rna_base].functions] rna_base_func_keys = [f.identifier for f in rna_struct_dict[rna_base].functions]
else: else:
rna_base_prop_keys = [] rna_base_prop_keys = []
rna_base_func_keys= [] rna_base_func_keys = []
# rna_struct_path = full_rna_struct_path(rna_struct) # rna_struct_path = full_rna_struct_path(rna_struct)
rna_struct_path = rna_full_path_dict[identifier] rna_struct_path = rna_full_path_dict[identifier]
for rna_prop_identifier, rna_prop in rna_struct.properties.items(): for rna_prop_identifier, rna_prop in rna_struct.properties.items():
if rna_prop_identifier=='RNA': continue if rna_prop_identifier == 'RNA' or \
if rna_id_ignore(rna_prop_identifier): continue rna_id_ignore(rna_prop_identifier) or \
if rna_prop_identifier in rna_base_prop_keys: continue rna_prop_identifier in rna_base_prop_keys:
continue
for rna_prop_ptr in (getattr(rna_prop, "fixed_type", None), getattr(rna_prop, "srna", None)): for rna_prop_ptr in (getattr(rna_prop, "fixed_type", None), getattr(rna_prop, "srna", None)):
# Does this property point to me? # Does this property point to me?
if rna_prop_ptr: if rna_prop_ptr:
rna_references_dict[rna_prop_ptr.identifier].append( "%s.%s" % (rna_struct_path, rna_prop_identifier) ) rna_references_dict[rna_prop_ptr.identifier].append("%s.%s" % (rna_struct_path, rna_prop_identifier))
for rna_func in rna_struct.functions: for rna_func in rna_struct.functions:
for rna_prop_identifier, rna_prop in rna_func.parameters.items(): for rna_prop_identifier, rna_prop in rna_func.parameters.items():
if rna_prop_identifier=='RNA': continue if rna_prop_identifier == 'RNA' or \
if rna_id_ignore(rna_prop_identifier): continue rna_id_ignore(rna_prop_identifier) or \
if rna_prop_identifier in rna_base_func_keys: continue rna_prop_identifier in rna_base_func_keys:
continue
try:
try: rna_prop_ptr = rna_prop.fixed_type rna_prop_ptr = rna_prop.fixed_type
except: rna_prop_ptr = None except:
rna_prop_ptr = None
# Does this property point to me? # Does this property point to me?
if rna_prop_ptr: if rna_prop_ptr:
rna_references_dict[rna_prop_ptr.identifier].append( "%s.%s" % (rna_struct_path, rna_func.identifier) ) rna_references_dict[rna_prop_ptr.identifier].append("%s.%s" % (rna_struct_path, rna_func.identifier))
# Store nested children # Store nested children
@@ -309,11 +522,11 @@ def BuildRNAInfo():
if rna_base: if rna_base:
rna_funcs = rna_functions_dict[identifier] rna_funcs = rna_functions_dict[identifier]
if rna_funcs: if rna_funcs:
# Remove inherited functions if we have any # Remove inherited functions if we have any
rna_base_funcs = rna_functions_dict__copy[rna_base] rna_base_funcs = rna_functions_dict__copy[rna_base]
rna_funcs[:] = [f for f in rna_funcs if f not in rna_base_funcs] rna_funcs[:] = [f for f in rna_funcs if f not in rna_base_funcs]
rna_functions_dict__copy.clear() rna_functions_dict__copy.clear()
del rna_functions_dict__copy del rna_functions_dict__copy
@@ -329,7 +542,7 @@ def BuildRNAInfo():
# continue # continue
#write_struct(rna_struct, '') #write_struct(rna_struct, '')
info_struct= GetInfoStructRNA(rna_struct) info_struct = GetInfoStructRNA(rna_struct)
if rna_base: if rna_base:
info_struct.base = GetInfoStructRNA(rna_struct_dict[rna_base]) info_struct.base = GetInfoStructRNA(rna_struct_dict[rna_base])
info_struct.nested = GetInfoStructRNA(rna_struct.nested) info_struct.nested = GetInfoStructRNA(rna_struct.nested)
@@ -347,9 +560,42 @@ def BuildRNAInfo():
for rna_info in InfoStructRNA.global_lookup.values(): for rna_info in InfoStructRNA.global_lookup.values():
rna_info.build() rna_info.build()
for prop in rna_info.properties:
prop.build()
for func in rna_info.functions:
func.build()
for prop in func.args:
prop.build()
if func.return_value:
func.return_value.build()
for rna_info in InfoStructRNA.global_lookup.values(): # now for operators
print(rna_info) op_mods = dir(bpy.ops)
return InfoStructRNA.global_lookup, InfoFunctionRNA.global_lookup, InfoPropertyRNA.global_lookup for op_mod_name in sorted(op_mods):
if op_mod_name.startswith('__') or op_mod_name in ("add", "remove"):
continue
op_mod = getattr(bpy.ops, op_mod_name)
operators = dir(op_mod)
for op in sorted(operators):
try:
rna_prop = getattr(op_mod, op).get_rna()
except AttributeError:
rna_prop = None
except TypeError:
rna_prop = None
if rna_prop:
GetInfoOperatorRNA(rna_prop.bl_rna)
for rna_info in InfoOperatorRNA.global_lookup.values():
rna_info.build()
for rna_prop in rna_info.args:
rna_prop.build()
#for rna_info in InfoStructRNA.global_lookup.values():
# print(rna_info)
return InfoStructRNA.global_lookup, InfoFunctionRNA.global_lookup, InfoOperatorRNA.global_lookup, InfoPropertyRNA.global_lookup

View File

@@ -143,7 +143,7 @@ rna_max = FloatProperty(name="Max", default=1.0, precision=3)
class WM_OT_properties_edit(bpy.types.Operator): class WM_OT_properties_edit(bpy.types.Operator):
'''Internal use (edit a property path)''' '''Internal use (edit a property path)'''
bl_idname = "wm.properties_edit" bl_idname = "wm.properties_edit"
bl_label = "Edit Property!" bl_label = "Edit Property"
path = rna_path path = rna_path
property = rna_property property = rna_property
@@ -196,7 +196,7 @@ class WM_OT_properties_edit(bpy.types.Operator):
prop_ui['description'] = self.properties.description prop_ui['description'] = self.properties.description
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
@@ -216,7 +216,7 @@ class WM_OT_properties_edit(bpy.types.Operator):
#return wm.invoke_props_popup(self, event) #return wm.invoke_props_popup(self, event)
wm.invoke_props_popup(self, event) wm.invoke_props_popup(self, event)
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
class WM_OT_properties_add(bpy.types.Operator): class WM_OT_properties_add(bpy.types.Operator):
@@ -242,7 +242,7 @@ class WM_OT_properties_add(bpy.types.Operator):
property = unique_name(item.keys()) property = unique_name(item.keys())
item[property] = 1.0 item[property] = 1.0
return ('FINISHED',) return {'FINISHED'}
class WM_OT_properties_remove(bpy.types.Operator): class WM_OT_properties_remove(bpy.types.Operator):
@@ -256,4 +256,4 @@ class WM_OT_properties_remove(bpy.types.Operator):
def execute(self, context): def execute(self, context):
item = eval("context.%s" % self.properties.path) item = eval("context.%s" % self.properties.path)
del item[self.properties.property] del item[self.properties.property]
return ('FINISHED',) return {'FINISHED'}

View File

@@ -23,6 +23,7 @@ from math import cos, sin, pi
# could this be stored elsewhere? # could this be stored elsewhere?
def metarig_template(): def metarig_template():
# generated by rigify.write_meta_rig # generated by rigify.write_meta_rig
bpy.ops.object.mode_set(mode='EDIT') bpy.ops.object.mode_set(mode='EDIT')
@@ -607,17 +608,16 @@ class AddHuman(bpy.types.Operator):
bones.remove(bones[0]) bones.remove(bones[0])
metarig_template() metarig_template()
bpy.ops.object.mode_set(mode=mode_orig) bpy.ops.object.mode_set(mode=mode_orig)
return ('FINISHED',) return {'FINISHED'}
# Register the operator # Register the operator
bpy.ops.add(AddHuman) bpy.types.register(AddHuman)
# Add to a menu # Add to a menu
import dynamic_menu menu_func = (lambda self, context: self.layout.operator(AddHuman.bl_idname,
icon='OUTLINER_OB_ARMATURE', text="Human (Meta-Rig)"))
menu_func = (lambda self, context: self.layout.operator(AddHuman.bl_idname, icon='OUTLINER_OB_ARMATURE', text="Human (Meta-Rig)")) bpy.types.INFO_MT_armature_add.append(menu_func)
menu_item = dynamic_menu.add(bpy.types.INFO_MT_armature_add, menu_func)
if __name__ == "__main__": if __name__ == "__main__":
bpy.ops.mesh.armature_human_advanced_add() bpy.ops.mesh.armature_human_advanced_add()

View File

@@ -122,18 +122,16 @@ class AddTorus(bpy.types.Operator):
ob_new.location = tuple(context.scene.cursor_location) ob_new.location = tuple(context.scene.cursor_location)
return ('FINISHED',) return {'FINISHED'}
# Register the operator # Register the operator
bpy.ops.add(AddTorus) bpy.types.register(AddTorus)
# Add to a menu
import dynamic_menu
# Add to the menu
menu_func = (lambda self, context: self.layout.operator(AddTorus.bl_idname, menu_func = (lambda self, context: self.layout.operator(AddTorus.bl_idname,
text="Torus", icon='MESH_DONUT')) text="Torus", icon='MESH_DONUT'))
menu_item = dynamic_menu.add(bpy.types.INFO_MT_mesh_add, menu_func) bpy.types.INFO_MT_mesh_add.append(menu_func)
if __name__ == "__main__": if __name__ == "__main__":
bpy.ops.mesh.primitive_torus_add() bpy.ops.mesh.primitive_torus_add()

View File

@@ -79,10 +79,10 @@ def execute(context):
try: try:
line = sc.history[-1].line line = sc.history[-1].line
except: except:
return ('CANCELLED',) return {'CANCELLED'}
if sc.console_type != 'PYTHON': if sc.console_type != 'PYTHON':
return ('CANCELLED',) return {'CANCELLED'}
console, stdout, stderr = get_console(hash(context.region)) console, stdout, stderr = get_console(hash(context.region))
@@ -136,7 +136,7 @@ def execute(context):
if output_err: if output_err:
add_scrollback(output_err, 'ERROR') add_scrollback(output_err, 'ERROR')
return ('FINISHED',) return {'FINISHED'}
def autocomplete(context): def autocomplete(context):
@@ -150,10 +150,10 @@ def autocomplete(context):
line = current_line.line line = current_line.line
if not console: if not console:
return ('CANCELLED',) return {'CANCELLED'}
if sc.console_type != 'PYTHON': if sc.console_type != 'PYTHON':
return ('CANCELLED',) return {'CANCELLED'}
# This function isnt aware of the text editor or being an operator # This function isnt aware of the text editor or being an operator
# just does the autocomp then copy its results back # just does the autocomp then copy its results back
@@ -172,7 +172,7 @@ def autocomplete(context):
context.area.tag_redraw() context.area.tag_redraw()
return ('FINISHED',) return {'FINISHED'}
def banner(context): def banner(context):
@@ -195,4 +195,4 @@ def banner(context):
console = get_console(hash(context.region))[0] console = get_console(hash(context.region))[0]
console.locals["C"] = bpy.context console.locals["C"] = bpy.context
return ('FINISHED',) return {'FINISHED'}

View File

@@ -49,7 +49,7 @@ def execute(context):
try: try:
line = sc.history[-1].line line = sc.history[-1].line
except: except:
return ('CANCELLED',) return {'CANCELLED'}
bpy.ops.console.scrollback_append(text=sc.prompt + line, type='INPUT') bpy.ops.console.scrollback_append(text=sc.prompt + line, type='INPUT')
@@ -60,13 +60,13 @@ def execute(context):
remove_duplicates=True) remove_duplicates=True)
sc.prompt = os.getcwd() + PROMPT sc.prompt = os.getcwd() + PROMPT
return ('FINISHED',) return {'FINISHED'}
def autocomplete(context): def autocomplete(context):
# sc = context.space_data # sc = context.space_data
# TODO # TODO
return ('CANCELLED',) return {'CANCELLED'}
def banner(context): def banner(context):
@@ -75,4 +75,4 @@ def banner(context):
shell_run("bash --version") shell_run("bash --version")
sc.prompt = os.getcwd() + PROMPT sc.prompt = os.getcwd() + PROMPT
return ('FINISHED',) return {'FINISHED'}

View File

@@ -65,11 +65,11 @@ class MeshSelectInteriorFaces(bpy.types.Operator):
def execute(self, context): def execute(self, context):
main(context) main(context)
return ('FINISHED',) return {'FINISHED'}
# Register the operator # Register the operator
bpy.ops.add(MeshSelectInteriorFaces) bpy.types.register(MeshSelectInteriorFaces)
if __name__ == "__main__": if __name__ == "__main__":
bpy.ops.mesh.faces_select_interior() bpy.ops.mesh.faces_select_interior()

View File

@@ -249,17 +249,16 @@ def mesh_faces_extend(me, faces, mat_idx = 0):
def getSelectedEdges(context, me, ob): def getSelectedEdges(context, me, ob):
MESH_MODE= context.scene.tool_settings.mesh_selection_mode MESH_MODE = tuple(context.tool_settings.mesh_selection_mode)
context.tool_settings.mesh_selection_mode = False, True, False
if MESH_MODE in ('EDGE', 'VERTEX'): if not MESH_MODE[2]:
context.scene.tool_settings.mesh_selection_mode = 'EDGE'
edges= [ ed for ed in me.edges if ed.selected ] edges= [ ed for ed in me.edges if ed.selected ]
# print len(edges), len(me.edges) # print len(edges), len(me.edges)
context.scene.tool_settings.mesh_selection_mode = MESH_MODE context.scene.tool_settings.mesh_selection_mode = MESH_MODE
return edges return edges
if MESH_MODE == 'FACE': else:
context.scene.tool_settings.mesh_selection_mode = 'EDGE'
# value is [edge, face_sel_user_in] # value is [edge, face_sel_user_in]
edge_dict= dict((ed.key, [ed, 0]) for ed in me.edges) edge_dict= dict((ed.key, [ed, 0]) for ed in me.edges)
@@ -268,7 +267,7 @@ def getSelectedEdges(context, me, ob):
for edkey in f.edge_keys: for edkey in f.edge_keys:
edge_dict[edkey][1] += 1 edge_dict[edkey][1] += 1
context.scene.tool_settings.mesh_selection_mode = MESH_MODE context.tool_settings.mesh_selection_mode = MESH_MODE
return [ ed_data[0] for ed_data in edge_dict.values() if ed_data[1] == 1 ] return [ ed_data[0] for ed_data in edge_dict.values() if ed_data[1] == 1 ]
@@ -644,15 +643,14 @@ class MESH_OT_skin(bpy.types.Operator):
def execute(self, context): def execute(self, context):
main(context) main(context)
return ('FINISHED',) return {'FINISHED'}
# Register the operator # Register the operator
bpy.ops.add(MESH_OT_skin) bpy.types.register(MESH_OT_skin)
# Add to a menu # Add to a menu
import dynamic_menu bpy.types.VIEW3D_MT_edit_mesh_faces.append((lambda self, context: self.layout.operator("mesh.skin", text="Bridge Faces")))
menu_item = dynamic_menu.add(bpy.types.VIEW3D_MT_edit_mesh_faces, (lambda self, context: self.layout.operator("mesh.skin", text="Bridge Faces")) )
if __name__ == "__main__": if __name__ == "__main__":
bpy.ops.mesh.skin() bpy.ops.mesh.skin()

View File

@@ -57,13 +57,13 @@ class SelectPattern(bpy.types.Operator):
elif not self.properties.extend: elif not self.properties.extend:
item.selected = False item.selected = False
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.manager wm = context.manager
# return wm.invoke_props_popup(self, event) # return wm.invoke_props_popup(self, event)
wm.invoke_props_popup(self, event) wm.invoke_props_popup(self, event)
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
@@ -84,27 +84,45 @@ class SubdivisionSet(bpy.types.Operator):
bl_undo = True bl_undo = True
level = IntProperty(name="Level", level = IntProperty(name="Level",
default=1, min=0, max=100, soft_min=0, soft_max=6) default=1, min=-100, max=100, soft_min=-6, soft_max=6)
relative = BoolProperty(name="Relative", description="Apply the subsurf level as an offset relative to the current level", default=False)
def poll(self, context): def poll(self, context):
ob = context.active_object obs = context.selected_editable_objects
return (ob and ob.type == 'MESH') return (obs is not None)
def execute(self, context): def execute(self, context):
level = self.properties.level level = self.properties.level
relative = self.properties.relative
if relative and level == 0:
return {'CANCELLED'} # nothing to do
def set_object_subd(obj): def set_object_subd(obj):
for mod in obj.modifiers: for mod in obj.modifiers:
if mod.type == 'MULTIRES': if mod.type == 'MULTIRES':
if level < mod.total_levels: if level <= mod.total_levels:
if obj.mode == 'SCULPT' and mod.sculpt_levels != level: if obj.mode == 'SCULPT':
mod.sculpt_levels = level if relative:
elif obj.mode == 'OBJECT' and mod.levels != level: mod.sculpt_levels += level
mod.levels = level else:
if mod.sculpt_levels != level:
mod.sculpt_levels = level
elif obj.mode == 'OBJECT':
if relative:
mod.levels += level
else:
if mod.levels != level:
mod.levels = level
return return
elif mod.type == 'SUBSURF': elif mod.type == 'SUBSURF':
if mod.levels != level: if relative:
mod.levels = level mod.levels += level
else:
if mod.levels != level:
mod.levels = level
return return
# adda new modifier # adda new modifier
@@ -114,7 +132,7 @@ class SubdivisionSet(bpy.types.Operator):
for obj in context.selected_editable_objects: for obj in context.selected_editable_objects:
set_object_subd(obj) set_object_subd(obj)
return ('FINISHED',) return {'FINISHED'}
class Retopo(bpy.types.Operator): class Retopo(bpy.types.Operator):
@@ -128,9 +146,175 @@ class Retopo(bpy.types.Operator):
def execute(self, context): def execute(self, context):
import retopo import retopo
retopo.main() retopo.main()
return ('FINISHED',) return {'FINISHED'}
bpy.ops.add(SelectPattern) class ShapeTransfer(bpy.types.Operator):
bpy.ops.add(SubdivisionSet) '''Copy the active objects current shape to other selected objects with the same number of verts'''
bpy.ops.add(Retopo)
bl_idname = "object.shape_key_transfer"
bl_label = "Transfer Shape Key"
bl_register = True
bl_undo = True
mode = EnumProperty(items=(
('OFFSET', "Offset", "Apply the relative positional offset"),
('RELATIVE_FACE', "Relative Face", "Calculate the geometricly relative position (using faces)."),
('RELATIVE_EDGE', "Relative Edge", "Calculate the geometricly relative position (using edges).")),
name="Transformation Mode",
description="Method to apply relative shape positions to the new shape",
default='OFFSET')
use_clamp = BoolProperty(name="Clamp Offset",
description="Clamp the transformation to the distance each vertex moves in the original shape.",
default=False)
def _main(self, ob_act, objects, mode='OFFSET', use_clamp=False):
def me_nos(verts):
return [v.normal.copy() for v in verts]
def me_cos(verts):
return [v.co.copy() for v in verts]
def ob_add_shape(ob):
me = ob.data
ob.add_shape_key(from_mix=False)
if len(me.shape_keys.keys) == 1:
ob.add_shape_key(from_mix=False) # we need a rest
ob.active_shape_key_index = len(me.shape_keys.keys) - 1
ob.shape_key_lock = True
from Geometry import BarycentricTransform
from Mathutils import Vector
if use_clamp and mode == 'OFFSET':
use_clamp = False
me = ob_act.data
orig_shape_coords = me_cos(ob_act.active_shape_key.data)
orig_normals = me_nos(me.verts)
orig_coords = me_cos(me.verts)
for ob_other in objects:
me_other = ob_other.data
if len(me_other.verts) != len(me.verts):
self.report({'WARNING'}, "Skipping '%s', vertex count differs" % ob_other.name)
continue
target_normals = me_nos(me_other.verts)
target_coords = me_cos(me_other.verts)
ob_add_shape(ob_other)
# editing the final coords, only list that stores wrapped coords
target_shape_coords = [v.co for v in ob_other.active_shape_key.data]
median_coords = [[] for i in range(len(me.verts))]
# Method 1, edge
if mode == 'OFFSET':
for i, vert_cos in enumerate(median_coords):
vert_cos.append(target_coords[i] + (orig_shape_coords[i] - orig_coords[i]))
elif mode == 'RELATIVE_FACE':
for face in me.faces:
i1, i2, i3, i4 = face.verts_raw
if i4 != 0:
pt = BarycentricTransform(orig_shape_coords[i1],
orig_coords[i4], orig_coords[i1], orig_coords[i2],
target_coords[i4], target_coords[i1], target_coords[i2])
median_coords[i1].append(pt)
pt = BarycentricTransform(orig_shape_coords[i2],
orig_coords[i1], orig_coords[i2], orig_coords[i3],
target_coords[i1], target_coords[i2], target_coords[i3])
median_coords[i2].append(pt)
pt = BarycentricTransform(orig_shape_coords[i3],
orig_coords[i2], orig_coords[i3], orig_coords[i4],
target_coords[i2], target_coords[i3], target_coords[i4])
median_coords[i3].append(pt)
pt = BarycentricTransform(orig_shape_coords[i4],
orig_coords[i3], orig_coords[i4], orig_coords[i1],
target_coords[i3], target_coords[i4], target_coords[i1])
median_coords[i4].append(pt)
else:
pt = BarycentricTransform(orig_shape_coords[i1],
orig_coords[i3], orig_coords[i1], orig_coords[i2],
target_coords[i3], target_coords[i1], target_coords[i2])
median_coords[i1].append(pt)
pt = BarycentricTransform(orig_shape_coords[i2],
orig_coords[i1], orig_coords[i2], orig_coords[i3],
target_coords[i1], target_coords[i2], target_coords[i3])
median_coords[i2].append(pt)
pt = BarycentricTransform(orig_shape_coords[i3],
orig_coords[i2], orig_coords[i3], orig_coords[i1],
target_coords[i2], target_coords[i3], target_coords[i1])
median_coords[i3].append(pt)
elif mode == 'RELATIVE_EDGE':
for ed in me.edges:
i1, i2 = ed.verts
v1, v2 = orig_coords[i1], orig_coords[i2]
edge_length = (v1 - v2).length
n1loc = v1 + orig_normals[i1] * edge_length
n2loc = v2 + orig_normals[i2] * edge_length
# now get the target nloc's
v1_to, v2_to = target_coords[i1], target_coords[i2]
edlen_to = (v1_to - v2_to).length
n1loc_to = v1_to + target_normals[i1] * edlen_to
n2loc_to = v2_to + target_normals[i2] * edlen_to
pt = BarycentricTransform(orig_shape_coords[i1],
v2, v1, n1loc,
v2_to, v1_to, n1loc_to)
median_coords[i1].append(pt)
pt = BarycentricTransform(orig_shape_coords[i2],
v1, v2, n2loc,
v1_to, v2_to, n2loc_to)
median_coords[i2].append(pt)
# apply the offsets to the new shape
from functools import reduce
VectorAdd = Vector.__add__
for i, vert_cos in enumerate(median_coords):
if vert_cos:
co = reduce(VectorAdd, vert_cos) / len(vert_cos)
if use_clamp:
# clamp to the same movement as the original
# breaks copy between different scaled meshes.
len_from = (orig_shape_coords[i] - orig_coords[i]).length
ofs = co - target_coords[i]
ofs.length = len_from
co = target_coords[i] + ofs
target_shape_coords[i][:] = co
return {'FINISHED'}
def poll(self, context):
obj = context.active_object
return (obj and obj.mode != 'EDIT')
def execute(self, context):
C = bpy.context
ob_act = C.active_object
objects = [ob for ob in C.selected_editable_objects if ob != ob_act]
return self._main(ob_act, objects, self.properties.mode, self.properties.use_clamp)
bpy.types.register(SelectPattern)
bpy.types.register(SubdivisionSet)
bpy.types.register(Retopo)
bpy.types.register(ShapeTransfer)

View File

@@ -40,7 +40,7 @@ class AddPresetBase(bpy.types.Operator):
def execute(self, context): def execute(self, context):
if not self.properties.name: if not self.properties.name:
return ('FINISHED',) return {'FINISHED'}
filename = self._as_filename(self.properties.name) + ".py" filename = self._as_filename(self.properties.name) + ".py"
@@ -53,7 +53,7 @@ class AddPresetBase(bpy.types.Operator):
file_preset.close() file_preset.close()
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.manager wm = context.manager
@@ -61,7 +61,7 @@ class AddPresetBase(bpy.types.Operator):
#return wm.invoke_props_popup(self, event) #return wm.invoke_props_popup(self, event)
wm.invoke_props_popup(self, event) wm.invoke_props_popup(self, event)
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
class AddPresetRender(AddPresetBase): class AddPresetRender(AddPresetBase):
@@ -125,6 +125,6 @@ class AddPresetCloth(AddPresetBase):
preset_subdir = "cloth" preset_subdir = "cloth"
bpy.ops.add(AddPresetRender) bpy.types.register(AddPresetRender)
bpy.ops.add(AddPresetSSS) bpy.types.register(AddPresetSSS)
bpy.ops.add(AddPresetCloth) bpy.types.register(AddPresetCloth)

View File

@@ -17,37 +17,40 @@
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# #
# ***** END GPL LICENCE BLOCK ***** # ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
# <pep8 compliant>
# History # History
# #
# Originally written by Matt Ebb # Originally written by Matt Ebb
import bpy import bpy
import subprocess, os, platform import subprocess
import os
import platform
# from BKE_add_image_extension() # from BKE_add_image_extension()
img_format_exts = { img_format_exts = {
'IRIS':'.rgb', 'IRIS': '.rgb',
'RADHDR':'.hdr', 'RADHDR': '.hdr',
'PNG':'png', 'PNG': 'png',
'TARGA':'tga', 'TARGA': 'tga',
'RAWTARGA':'tga', 'RAWTARGA': 'tga',
'BMP':'bmp', 'BMP': 'bmp',
'TIFF':'tif', 'TIFF': 'tif',
'OPENEXR':'exr', 'OPENEXR': 'exr',
'MULTILAYER':'exr', 'MULTILAYER': 'exr',
'CINEON':'cin', 'CINEON': 'cin',
'DPX':'dpx', 'DPX': 'dpx',
'JPEG':'jpg', 'JPEG': 'jpg',
'JPEG2000':'jp2', 'JPEG2000': 'jp2',
'QUICKTIME_QTKIT':'mov', 'QUICKTIME_QTKIT': 'mov',
'QUICKTIME_CARBON':'mov', 'QUICKTIME_CARBON': 'mov',
'AVIRAW':'avi', 'AVIRAW': 'avi',
'AVIJPEG':'avi', 'AVIJPEG': 'avi',
'AVICODEC':'avi', 'AVICODEC': 'avi',
'XVID':'avi', 'XVID': 'avi',
'THEORA':'ogg', 'THEORA': 'ogg',
} }
movie_formats = ('QUICKTIME_QTKIT', movie_formats = ('QUICKTIME_QTKIT',
@@ -56,8 +59,8 @@ movie_formats = ('QUICKTIME_QTKIT',
'AVIJPEG', 'AVIJPEG',
'AVICODEC', 'AVICODEC',
'XVID', 'XVID',
'THEORA' 'THEORA')
)
def guess_player_path(preset): def guess_player_path(preset):
if preset == 'BLENDER24': if preset == 'BLENDER24':
@@ -146,4 +149,4 @@ class PlayRenderedAnim(bpy.types.Operator):
return('FINISHED',) return('FINISHED',)
bpy.ops.add(PlayRenderedAnim) bpy.types.register(PlayRenderedAnim)

View File

@@ -257,16 +257,13 @@ class FollowActiveQuads(bpy.types.Operator):
def execute(self, context): def execute(self, context):
main(context, self) main(context, self)
return ('FINISHED',) return {'FINISHED'}
bpy.ops.add(FollowActiveQuads) bpy.types.register(FollowActiveQuads)
# Add to a menu # Add to a menu
import dynamic_menu
menu_func = (lambda self, context: self.layout.operator(FollowActiveQuads.bl_idname)) menu_func = (lambda self, context: self.layout.operator(FollowActiveQuads.bl_idname))
bpy.types.VIEW3D_MT_uv_map.append(menu_func)
menu_item = dynamic_menu.add(bpy.types.VIEW3D_MT_uv_map, menu_func)
if __name__ == '__main__': if __name__ == '__main__':
bpy.ops.uv.follow_active_quads() bpy.ops.uv.follow_active_quads()

View File

@@ -1109,6 +1109,8 @@ def main(context, island_margin, projection_limit):
""" """
from bpy.props import * from bpy.props import *
class SmartProject(bpy.types.Operator): class SmartProject(bpy.types.Operator):
'''This script projection unwraps the selected faces of a mesh. it operates on all selected mesh objects, and can be used unwrap selected faces, or all faces.''' '''This script projection unwraps the selected faces of a mesh. it operates on all selected mesh objects, and can be used unwrap selected faces, or all faces.'''
bl_idname = "uv.smart_project" bl_idname = "uv.smart_project"
@@ -1130,18 +1132,15 @@ class SmartProject(bpy.types.Operator):
def execute(self, context): def execute(self, context):
main(context, self.properties.island_margin, self.properties.angle_limit) main(context, self.properties.island_margin, self.properties.angle_limit)
return ('FINISHED',) return {'FINISHED'}
bpy.ops.add(SmartProject) bpy.types.register(SmartProject)
# Add to a menu # Add to a menu
import dynamic_menu
menu_func = (lambda self, context: self.layout.operator(SmartProject.bl_idname, menu_func = (lambda self, context: self.layout.operator(SmartProject.bl_idname,
text="Smart Project")) text="Smart Project"))
menu_item = dynamic_menu.add(bpy.types.VIEW3D_MT_uv_map, menu_func) bpy.types.VIEW3D_MT_uv_map.append(menu_func)
if __name__ == '__main__': if __name__ == '__main__':
bpy.ops.uv.smart_project() bpy.ops.uv.smart_project()

View File

@@ -158,24 +158,23 @@ class VertexPaintDirt(bpy.types.Operator):
dirt_only = BoolProperty(name="Dirt Only", description="Dont calculate cleans for convex areas", default=False) dirt_only = BoolProperty(name="Dirt Only", description="Dont calculate cleans for convex areas", default=False)
def execute(self, context): def execute(self, context):
sce = context.scene obj = context.object
ob = context.object
if not ob or ob.type != 'MESH': if not obj or obj.type != 'MESH':
print('Error, no active mesh object, aborting.') print('Error, no active mesh object, aborting.')
return('CANCELLED',) return('CANCELLED',)
me = ob.data mesh = obj.data
t = time.time() t = time.time()
applyVertexDirt(me, self.properties.blur_iterations, self.properties.blur_strength, math.radians(self.properties.dirt_angle), math.radians(self.properties.clean_angle), self.properties.dirt_only) applyVertexDirt(mesh, self.properties.blur_iterations, self.properties.blur_strength, math.radians(self.properties.dirt_angle), math.radians(self.properties.clean_angle), self.properties.dirt_only)
print('Dirt calculated in %.6f' % (time.time() - t)) print('Dirt calculated in %.6f' % (time.time() - t))
return('FINISHED',) return('FINISHED',)
bpy.ops.add(VertexPaintDirt) bpy.types.register(VertexPaintDirt)
if __name__ == "__main__": if __name__ == "__main__":
bpy.ops.mesh.vertex_paint_dirt() bpy.ops.mesh.vertex_paint_dirt()

View File

@@ -34,7 +34,7 @@ class MESH_OT_delete_edgeloop(bpy.types.Operator):
bpy.ops.mesh.select_more() bpy.ops.mesh.select_more()
bpy.ops.mesh.remove_doubles() bpy.ops.mesh.remove_doubles()
return ('FINISHED',) return {'FINISHED'}
rna_path_prop = StringProperty(name="Context Attributes", rna_path_prop = StringProperty(name="Context Attributes",
description="rna context string", maxlen=1024, default="") description="rna context string", maxlen=1024, default="")
@@ -60,15 +60,16 @@ def context_path_validate(context, path):
def execute_context_assign(self, context): def execute_context_assign(self, context):
if context_path_validate(context, self.properties.path) is Ellipsis: if context_path_validate(context, self.properties.path) is Ellipsis:
return ('PASS_THROUGH',) return {'PASS_THROUGH'}
exec("context.%s=self.properties.value" % self.properties.path) exec("context.%s=self.properties.value" % self.properties.path)
return ('FINISHED',) return {'FINISHED'}
class WM_OT_context_set_boolean(bpy.types.Operator): class WM_OT_context_set_boolean(bpy.types.Operator):
'''Set a context value.''' '''Set a context value.'''
bl_idname = "wm.context_set_boolean" bl_idname = "wm.context_set_boolean"
bl_label = "Context Set" bl_label = "Context Set Boolean"
bl_undo = True
path = rna_path_prop path = rna_path_prop
value = BoolProperty(name="Value", value = BoolProperty(name="Value",
@@ -81,6 +82,7 @@ class WM_OT_context_set_int(bpy.types.Operator): # same as enum
'''Set a context value.''' '''Set a context value.'''
bl_idname = "wm.context_set_int" bl_idname = "wm.context_set_int"
bl_label = "Context Set" bl_label = "Context Set"
bl_undo = True
path = rna_path_prop path = rna_path_prop
value = IntProperty(name="Value", description="Assign value", default=0) value = IntProperty(name="Value", description="Assign value", default=0)
@@ -91,7 +93,8 @@ class WM_OT_context_set_int(bpy.types.Operator): # same as enum
class WM_OT_context_set_float(bpy.types.Operator): # same as enum class WM_OT_context_set_float(bpy.types.Operator): # same as enum
'''Set a context value.''' '''Set a context value.'''
bl_idname = "wm.context_set_float" bl_idname = "wm.context_set_float"
bl_label = "Context Set" bl_label = "Context Set Float"
bl_undo = True
path = rna_path_prop path = rna_path_prop
value = FloatProperty(name="Value", value = FloatProperty(name="Value",
@@ -103,7 +106,8 @@ class WM_OT_context_set_float(bpy.types.Operator): # same as enum
class WM_OT_context_set_string(bpy.types.Operator): # same as enum class WM_OT_context_set_string(bpy.types.Operator): # same as enum
'''Set a context value.''' '''Set a context value.'''
bl_idname = "wm.context_set_string" bl_idname = "wm.context_set_string"
bl_label = "Context Set" bl_label = "Context Set String"
bl_undo = True
path = rna_path_prop path = rna_path_prop
value = StringProperty(name="Value", value = StringProperty(name="Value",
@@ -115,7 +119,8 @@ class WM_OT_context_set_string(bpy.types.Operator): # same as enum
class WM_OT_context_set_enum(bpy.types.Operator): class WM_OT_context_set_enum(bpy.types.Operator):
'''Set a context value.''' '''Set a context value.'''
bl_idname = "wm.context_set_enum" bl_idname = "wm.context_set_enum"
bl_label = "Context Set" bl_label = "Context Set Enum"
bl_undo = True
path = rna_path_prop path = rna_path_prop
value = StringProperty(name="Value", value = StringProperty(name="Value",
@@ -125,27 +130,48 @@ class WM_OT_context_set_enum(bpy.types.Operator):
execute = execute_context_assign execute = execute_context_assign
class WM_OT_context_set_value(bpy.types.Operator):
'''Set a context value.'''
bl_idname = "wm.context_set_value"
bl_label = "Context Set Value"
bl_undo = True
path = rna_path_prop
value = StringProperty(name="Value",
description="Assignment value (as a string)",
maxlen=1024, default="")
def execute(self, context):
if context_path_validate(context, self.properties.path) is Ellipsis:
return {'PASS_THROUGH'}
exec("context.%s=%s" % (self.properties.path, self.properties.value))
return {'FINISHED'}
class WM_OT_context_toggle(bpy.types.Operator): class WM_OT_context_toggle(bpy.types.Operator):
'''Toggle a context value.''' '''Toggle a context value.'''
bl_idname = "wm.context_toggle" bl_idname = "wm.context_toggle"
bl_label = "Context Toggle" bl_label = "Context Toggle"
bl_undo = True
path = rna_path_prop path = rna_path_prop
def execute(self, context): def execute(self, context):
if context_path_validate(context, self.properties.path) is Ellipsis: if context_path_validate(context, self.properties.path) is Ellipsis:
return ('PASS_THROUGH',) return {'PASS_THROUGH'}
exec("context.%s=not (context.%s)" % exec("context.%s=not (context.%s)" %
(self.properties.path, self.properties.path)) (self.properties.path, self.properties.path))
return ('FINISHED',) return {'FINISHED'}
class WM_OT_context_toggle_enum(bpy.types.Operator): class WM_OT_context_toggle_enum(bpy.types.Operator):
'''Toggle a context value.''' '''Toggle a context value.'''
bl_idname = "wm.context_toggle_enum" bl_idname = "wm.context_toggle_enum"
bl_label = "Context Toggle Values" bl_label = "Context Toggle Values"
bl_undo = True
path = rna_path_prop path = rna_path_prop
value_1 = StringProperty(name="Value", \ value_1 = StringProperty(name="Value", \
@@ -157,14 +183,14 @@ class WM_OT_context_toggle_enum(bpy.types.Operator):
def execute(self, context): def execute(self, context):
if context_path_validate(context, self.properties.path) is Ellipsis: if context_path_validate(context, self.properties.path) is Ellipsis:
return ('PASS_THROUGH',) return {'PASS_THROUGH'}
exec("context.%s = ['%s', '%s'][context.%s!='%s']" % \ exec("context.%s = ['%s', '%s'][context.%s!='%s']" % \
(self.properties.path, self.properties.value_1,\ (self.properties.path, self.properties.value_1,\
self.properties.value_2, self.properties.path, self.properties.value_2, self.properties.path,
self.properties.value_2)) self.properties.value_2))
return ('FINISHED',) return {'FINISHED'}
class WM_OT_context_cycle_int(bpy.types.Operator): class WM_OT_context_cycle_int(bpy.types.Operator):
@@ -172,6 +198,8 @@ class WM_OT_context_cycle_int(bpy.types.Operator):
vertex keys, groups' etc.''' vertex keys, groups' etc.'''
bl_idname = "wm.context_cycle_int" bl_idname = "wm.context_cycle_int"
bl_label = "Context Int Cycle" bl_label = "Context Int Cycle"
bl_undo = True
path = rna_path_prop path = rna_path_prop
reverse = rna_reverse_prop reverse = rna_reverse_prop
@@ -179,7 +207,7 @@ class WM_OT_context_cycle_int(bpy.types.Operator):
value = context_path_validate(context, self.properties.path) value = context_path_validate(context, self.properties.path)
if value is Ellipsis: if value is Ellipsis:
return ('PASS_THROUGH',) return {'PASS_THROUGH'}
self.properties.value = value self.properties.value = value
if self.properties.reverse: if self.properties.reverse:
@@ -196,13 +224,14 @@ class WM_OT_context_cycle_int(bpy.types.Operator):
self.properties.value = - (1 << 32) self.properties.value = - (1 << 32)
execute_context_assign(self, context) execute_context_assign(self, context)
return ('FINISHED',) return {'FINISHED'}
class WM_OT_context_cycle_enum(bpy.types.Operator): class WM_OT_context_cycle_enum(bpy.types.Operator):
'''Toggle a context value.''' '''Toggle a context value.'''
bl_idname = "wm.context_cycle_enum" bl_idname = "wm.context_cycle_enum"
bl_label = "Context Enum Cycle" bl_label = "Context Enum Cycle"
bl_undo = True
path = rna_path_prop path = rna_path_prop
reverse = rna_reverse_prop reverse = rna_reverse_prop
@@ -211,7 +240,7 @@ class WM_OT_context_cycle_enum(bpy.types.Operator):
value = context_path_validate(context, self.properties.path) value = context_path_validate(context, self.properties.path)
if value is Ellipsis: if value is Ellipsis:
return ('PASS_THROUGH',) return {'PASS_THROUGH'}
orig_value = value orig_value = value
@@ -247,7 +276,7 @@ class WM_OT_context_cycle_enum(bpy.types.Operator):
# set the new value # set the new value
exec("context.%s=advance_enum" % self.properties.path) exec("context.%s=advance_enum" % self.properties.path)
return ('FINISHED',) return {'FINISHED'}
doc_id = StringProperty(name="Doc ID", doc_id = StringProperty(name="Doc ID",
description="", maxlen=1024, default="", hidden=True) description="", maxlen=1024, default="", hidden=True)
@@ -275,26 +304,26 @@ class WM_OT_doc_view(bpy.types.Operator):
def execute(self, context): def execute(self, context):
id_split = self.properties.doc_id.split('.') id_split = self.properties.doc_id.split('.')
if len(id_split) == 1: # rna, class if len(id_split) == 1: # rna, class
url = '%s/bpy.types.%s-class.html' % (self._prefix, id_split[0]) url = '%s/bpy.types.%s.html' % (self._prefix, id_split[0])
elif len(id_split) == 2: # rna, class.prop elif len(id_split) == 2: # rna, class.prop
class_name, class_prop = id_split class_name, class_prop = id_split
if hasattr(bpy.types, class_name.upper() + '_OT_' + class_prop): if hasattr(bpy.types, class_name.upper() + '_OT_' + class_prop):
url = '%s/bpy.ops.%s-module.html#%s' % \ url = '%s/bpy.ops.%s.html#bpy.ops.%s.%s' % \
(self._prefix, class_name, class_prop) (self._prefix, class_name, class_name, class_prop)
else: else:
# It so happens that epydoc nests these # It so happens that epydoc nests these, not sphinx
class_name_full = self._nested_class_string(class_name) # class_name_full = self._nested_class_string(class_name)
url = '%s/bpy.types.%s-class.html#%s' % \ url = '%s/bpy.types.%s.html#bpy.types.%s.%s' % \
(self._prefix, class_name_full, class_prop) (self._prefix, class_name, class_name, class_prop)
else: else:
return ('PASS_THROUGH',) return {'PASS_THROUGH'}
import webbrowser import webbrowser
webbrowser.open(url) webbrowser.open(url)
return ('FINISHED',) return {'FINISHED'}
class WM_OT_doc_edit(bpy.types.Operator): class WM_OT_doc_edit(bpy.types.Operator):
@@ -325,7 +354,7 @@ class WM_OT_doc_edit(bpy.types.Operator):
class_name, class_prop = doc_id.split('.') class_name, class_prop = doc_id.split('.')
if not doc_new: if not doc_new:
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
# check if this is an operator # check if this is an operator
op_name = class_name.upper() + '_OT_' + class_prop op_name = class_name.upper() + '_OT_' + class_prop
@@ -338,7 +367,7 @@ class WM_OT_doc_edit(bpy.types.Operator):
rna = op_class.bl_rna rna = op_class.bl_rna
doc_orig = rna.description doc_orig = rna.description
if doc_orig == doc_new: if doc_orig == doc_new:
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
print("op - old:'%s' -> new:'%s'" % (doc_orig, doc_new)) print("op - old:'%s' -> new:'%s'" % (doc_orig, doc_new))
upload["title"] = 'OPERATOR %s:%s' % (doc_id, doc_orig) upload["title"] = 'OPERATOR %s:%s' % (doc_id, doc_orig)
@@ -350,7 +379,7 @@ class WM_OT_doc_edit(bpy.types.Operator):
rna = getattr(bpy.types, class_name).bl_rna rna = getattr(bpy.types, class_name).bl_rna
doc_orig = rna.properties[class_prop].description doc_orig = rna.properties[class_prop].description
if doc_orig == doc_new: if doc_orig == doc_new:
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
print("rna - old:'%s' -> new:'%s'" % (doc_orig, doc_new)) print("rna - old:'%s' -> new:'%s'" % (doc_orig, doc_new))
upload["title"] = 'RNA %s:%s' % (doc_id, doc_orig) upload["title"] = 'RNA %s:%s' % (doc_id, doc_orig)
@@ -359,7 +388,7 @@ class WM_OT_doc_edit(bpy.types.Operator):
self._send_xmlrpc(upload) self._send_xmlrpc(upload)
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.manager wm = context.manager
@@ -374,28 +403,29 @@ class WM_OT_reload_scripts(bpy.types.Operator):
def execute(self, context): def execute(self, context):
MOD = type(bpy) MOD = type(bpy)
bpy.load_scripts(True) bpy.load_scripts(True)
return ('FINISHED',) return {'FINISHED'}
bpy.ops.add(MESH_OT_delete_edgeloop) bpy.types.register(MESH_OT_delete_edgeloop)
bpy.ops.add(WM_OT_context_set_boolean) bpy.types.register(WM_OT_context_set_boolean)
bpy.ops.add(WM_OT_context_set_int) bpy.types.register(WM_OT_context_set_int)
bpy.ops.add(WM_OT_context_set_float) bpy.types.register(WM_OT_context_set_float)
bpy.ops.add(WM_OT_context_set_string) bpy.types.register(WM_OT_context_set_string)
bpy.ops.add(WM_OT_context_set_enum) bpy.types.register(WM_OT_context_set_enum)
bpy.ops.add(WM_OT_context_toggle) bpy.types.register(WM_OT_context_set_value)
bpy.ops.add(WM_OT_context_toggle_enum) bpy.types.register(WM_OT_context_toggle)
bpy.ops.add(WM_OT_context_cycle_enum) bpy.types.register(WM_OT_context_toggle_enum)
bpy.ops.add(WM_OT_context_cycle_int) bpy.types.register(WM_OT_context_cycle_enum)
bpy.types.register(WM_OT_context_cycle_int)
bpy.ops.add(WM_OT_doc_view) bpy.types.register(WM_OT_doc_view)
bpy.ops.add(WM_OT_doc_edit) bpy.types.register(WM_OT_doc_edit)
bpy.ops.add(WM_OT_reload_scripts) bpy.types.register(WM_OT_reload_scripts)
# experemental! # experemental!
import rna_prop_ui import rna_prop_ui
bpy.ops.add(rna_prop_ui.WM_OT_properties_edit) bpy.types.register(rna_prop_ui.WM_OT_properties_edit)
bpy.ops.add(rna_prop_ui.WM_OT_properties_add) bpy.types.register(rna_prop_ui.WM_OT_properties_add)
bpy.ops.add(rna_prop_ui.WM_OT_properties_remove) bpy.types.register(rna_prop_ui.WM_OT_properties_remove)

View File

@@ -4,4 +4,4 @@ bpy.context.scene.render_data.resolution_percentage = 100
bpy.context.scene.render_data.pixel_aspect_x = 1 bpy.context.scene.render_data.pixel_aspect_x = 1
bpy.context.scene.render_data.pixel_aspect_y = 1 bpy.context.scene.render_data.pixel_aspect_y = 1
bpy.context.scene.render_data.fps = 24 bpy.context.scene.render_data.fps = 24
bpy.context.scene.render_data.fps_base = 1 bpy.context.scene.render_data.fps_base = 1

View File

@@ -4,4 +4,4 @@ bpy.context.scene.render_data.resolution_percentage = 100
bpy.context.scene.render_data.pixel_aspect_x = 1 bpy.context.scene.render_data.pixel_aspect_x = 1
bpy.context.scene.render_data.pixel_aspect_y = 1 bpy.context.scene.render_data.pixel_aspect_y = 1
bpy.context.scene.render_data.fps = 24 bpy.context.scene.render_data.fps = 24
bpy.context.scene.render_data.fps_base = 1 bpy.context.scene.render_data.fps_base = 1

View File

@@ -4,4 +4,4 @@ bpy.context.scene.render_data.resolution_percentage = 100
bpy.context.scene.render_data.pixel_aspect_x = 54 bpy.context.scene.render_data.pixel_aspect_x = 54
bpy.context.scene.render_data.pixel_aspect_y = 51 bpy.context.scene.render_data.pixel_aspect_y = 51
bpy.context.scene.render_data.fps = 25 bpy.context.scene.render_data.fps = 25
bpy.context.scene.render_data.fps_base = 1 bpy.context.scene.render_data.fps_base = 1

View File

@@ -4,4 +4,4 @@ bpy.context.scene.render_data.resolution_percentage = 100
bpy.context.scene.render_data.pixel_aspect_x = 64 bpy.context.scene.render_data.pixel_aspect_x = 64
bpy.context.scene.render_data.pixel_aspect_y = 45 bpy.context.scene.render_data.pixel_aspect_y = 45
bpy.context.scene.render_data.fps = 25 bpy.context.scene.render_data.fps = 25
bpy.context.scene.render_data.fps_base = 1 bpy.context.scene.render_data.fps_base = 1

View File

@@ -30,7 +30,7 @@ class ExportSomeData(bpy.types.Operator):
write_some_data(self.properties.path, context, self.properties.use_setting) write_some_data(self.properties.path, context, self.properties.use_setting)
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.manager wm = context.manager
@@ -38,7 +38,7 @@ class ExportSomeData(bpy.types.Operator):
if True: if True:
# File selector # File selector
wm.add_fileselect(self) # will run self.execute() wm.add_fileselect(self) # will run self.execute()
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
elif 0: elif 0:
# Redo popup # Redo popup
return wm.invoke_props_popup(self, event) # return wm.invoke_props_popup(self, event) #
@@ -46,13 +46,11 @@ class ExportSomeData(bpy.types.Operator):
return self.execute(context) return self.execute(context)
bpy.ops.add(ExportSomeData) bpy.types.register(ExportSomeData)
# Only needed if you want to add into a dynamic menu # Only needed if you want to add into a dynamic menu
import dynamic_menu
menu_func = lambda self, context: self.layout.operator("export.some_data", text="Example Exporter...") menu_func = lambda self, context: self.layout.operator("export.some_data", text="Example Exporter...")
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func) bpy.types.INFO_MT_file_export.append(menu_func)
# Use for running this script directly
if __name__ == "__main__": if __name__ == "__main__":
bpy.ops.export.some_data(path="/tmp/test.ply") bpy.ops.export.some_data(path="/tmp/test.ply")

View File

@@ -13,9 +13,9 @@ class SimpleOperator(bpy.types.Operator):
def execute(self, context): def execute(self, context):
main(context) main(context)
return ('FINISHED',) return {'FINISHED'}
bpy.ops.add(SimpleOperator) bpy.types.register(SimpleOperator)
if __name__ == "__main__": if __name__ == "__main__":
bpy.ops.object.simple_operator() bpy.ops.object.simple_operator()

View File

@@ -254,7 +254,7 @@ class DATA_PT_iksolver_itasc(DataButtonsPanel):
row = layout.row() row = layout.row()
row.prop(ob.pose, "ik_solver") row.prop(ob.pose, "ik_solver")
if itasc: if itasc:
layout.prop(itasc, "mode", expand=True) layout.prop(itasc, "mode", expand=True)
simulation = (itasc.mode == 'SIMULATION') simulation = (itasc.mode == 'SIMULATION')

View File

@@ -138,7 +138,7 @@ class Reload(bpy.types.Operator):
def execute(self, context): def execute(self, context):
DATA_PT_template.templates[:] = metarig_templates() DATA_PT_template.templates[:] = metarig_templates()
return ('FINISHED',) return {'FINISHED'}
def rigify_report_exception(operator, exception): def rigify_report_exception(operator, exception):
@@ -180,7 +180,7 @@ class Generate(bpy.types.Operator):
except rigify.RigifyError as rig_exception: except rigify.RigifyError as rig_exception:
rigify_report_exception(self, rig_exception) rigify_report_exception(self, rig_exception)
return ('FINISHED',) return {'FINISHED'}
class Validate(bpy.types.Operator): class Validate(bpy.types.Operator):
@@ -196,7 +196,7 @@ class Validate(bpy.types.Operator):
rigify.validate_rig(context, context.object) rigify.validate_rig(context, context.object)
except rigify.RigifyError as rig_exception: except rigify.RigifyError as rig_exception:
rigify_report_exception(self, rig_exception) rigify_report_exception(self, rig_exception)
return ('FINISHED',) return {'FINISHED'}
class Sample(bpy.types.Operator): class Sample(bpy.types.Operator):
@@ -219,7 +219,7 @@ class Sample(bpy.types.Operator):
if obj_gen: if obj_gen:
obj_gen.location.x = i * 1.0 obj_gen.location.x = i * 1.0
return ('FINISHED',) return {'FINISHED'}
class Graph(bpy.types.Operator): class Graph(bpy.types.Operator):
@@ -244,7 +244,7 @@ class Graph(bpy.types.Operator):
os.system("dot -Tpng %s > %s; gnome-open %s &" % (path_dot, path_png, path_png)) os.system("dot -Tpng %s > %s; gnome-open %s &" % (path_dot, path_png, path_png))
#os.system("python /b/xdot.py '%s' &" % path_dot) #os.system("python /b/xdot.py '%s' &" % path_dot)
return ('FINISHED',) return {'FINISHED'}
class AsScript(bpy.types.Operator): class AsScript(bpy.types.Operator):
@@ -267,7 +267,7 @@ class AsScript(bpy.types.Operator):
file.write(code) file.write(code)
file.close() file.close()
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
import os import os
@@ -275,7 +275,7 @@ class AsScript(bpy.types.Operator):
self.properties.path = os.path.splitext(bpy.data.filename)[0] + "-" + bpy.utils.clean_name(obj.name) + ".py" self.properties.path = os.path.splitext(bpy.data.filename)[0] + "-" + bpy.utils.clean_name(obj.name) + ".py"
wm = context.manager wm = context.manager
wm.add_fileselect(self) wm.add_fileselect(self)
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
# operators that use the GUI # operators that use the GUI
@@ -294,7 +294,7 @@ class ActiveAssign(bpy.types.Operator):
pose_templates = scene.pose_templates pose_templates = scene.pose_templates
template_name = DATA_PT_template.templates[pose_templates.active_template_index] template_name = DATA_PT_template.templates[pose_templates.active_template_index]
context.active_pose_bone["type"] = template_name context.active_pose_bone["type"] = template_name
return ('FINISHED',) return {'FINISHED'}
class ActiveClear(bpy.types.Operator): class ActiveClear(bpy.types.Operator):
@@ -310,14 +310,10 @@ class ActiveClear(bpy.types.Operator):
def execute(self, context): def execute(self, context):
scene = context.scene scene = context.scene
del context.active_pose_bone["type"] del context.active_pose_bone["type"]
return ('FINISHED',) return {'FINISHED'}
import space_info class INFO_MT_armature_metarig_add(bpy.types.Menu):
import dynamic_menu
class INFO_MT_armature_metarig_add(dynamic_menu.DynMenu):
bl_idname = "INFO_MT_armature_metarig_add" bl_idname = "INFO_MT_armature_metarig_add"
bl_label = "Meta-Rig" bl_label = "Meta-Rig"
@@ -336,18 +332,19 @@ bpy.types.register(DATA_PT_template)
bpy.types.register(PoseTemplateSettings) bpy.types.register(PoseTemplateSettings)
bpy.types.register(PoseTemplate) bpy.types.register(PoseTemplate)
bpy.ops.add(Reload) bpy.types.register(Reload)
bpy.ops.add(Generate) bpy.types.register(Generate)
bpy.ops.add(Validate) bpy.types.register(Validate)
bpy.ops.add(Sample) bpy.types.register(Sample)
bpy.ops.add(Graph) bpy.types.register(Graph)
bpy.ops.add(AsScript) bpy.types.register(AsScript)
bpy.ops.add(ActiveAssign) bpy.types.register(ActiveAssign)
bpy.ops.add(ActiveClear) bpy.types.register(ActiveClear)
bpy.types.register(INFO_MT_armature_metarig_add) bpy.types.register(INFO_MT_armature_metarig_add)
import space_info
menu_func = (lambda self, context: self.layout.menu("INFO_MT_armature_metarig_add", icon='OUTLINER_OB_ARMATURE')) menu_func = (lambda self, context: self.layout.menu("INFO_MT_armature_metarig_add", icon='OUTLINER_OB_ARMATURE'))
menu_item = dynamic_menu.add(bpy.types.INFO_MT_armature_add, menu_func) space_info.INFO_MT_armature_add.append(menu_func)

View File

@@ -602,16 +602,24 @@ class DATA_PT_modifiers(DataButtonsPanel):
layout.label(text="See Soft Body panel.") layout.label(text="See Soft Body panel.")
def SOLIDIFY(self, layout, ob, md, wide_ui): def SOLIDIFY(self, layout, ob, md, wide_ui):
layout.prop(md, "offset")
split = layout.split() split = layout.split()
col = split.column() col = split.column()
col.prop(md, "offset") col.label(text="Crease:")
col.prop(md, "edge_crease_inner",text="Inner")
col.prop(md, "edge_crease_outer", text="Outer")
col.prop(md, "edge_crease_rim", text="Rim")
if wide_ui:
col = split.column()
col.label()
col.prop(md, "use_rim") col.prop(md, "use_rim")
col.prop(md, "use_even_offset") col.prop(md, "use_even_offset")
col.prop(md, "use_quality_normals") col.prop(md, "use_quality_normals")
col.prop(md, "edge_crease_inner")
col.prop(md, "edge_crease_outer") # col = layout.column()
col.prop(md, "edge_crease_rim")
# col.label(text="Vertex Group:") # col.label(text="Vertex Group:")
# col.prop_object(md, "vertex_group", ob, "vertex_groups", text="") # col.prop_object(md, "vertex_group", ob, "vertex_groups", text="")
@@ -638,14 +646,15 @@ class DATA_PT_modifiers(DataButtonsPanel):
def UV_PROJECT(self, layout, ob, md, wide_ui): def UV_PROJECT(self, layout, ob, md, wide_ui):
if ob.type == 'MESH': if ob.type == 'MESH':
split = layout.split() split = layout.split()
col = split.column() col = split.column()
col.label(text="UV Layer:") col.label(text="Image:")
col.prop_object(md, "uv_layer", ob.data, "uv_textures", text="") col.prop(md, "image", text="")
if wide_ui: if wide_ui:
col = split.column() col = split.column()
col.label(text="Image:") col.label(text="UV Layer:")
col.prop(md, "image", text="") col.prop_object(md, "uv_layer", ob.data, "uv_textures", text="")
split = layout.split() split = layout.split()
col = split.column() col = split.column()
@@ -720,4 +729,4 @@ class DATA_PT_modifiers(DataButtonsPanel):
col.prop(md, "width", slider=True) col.prop(md, "width", slider=True)
col.prop(md, "narrowness", slider=True) col.prop(md, "narrowness", slider=True)
bpy.types.register(DATA_PT_modifiers) bpy.types.register(DATA_PT_modifiers)

View File

@@ -274,8 +274,7 @@ class RENDER_PT_game_stereo(RenderButtonsPanel):
# stereo: # stereo:
if stereo_mode == 'STEREO': if stereo_mode == 'STEREO':
layout.prop(gs, "stereo_mode") layout.prop(gs, "stereo_mode")
# layout.label(text="To do: Focal Length") # to be done after 2.5alpha0 is out layout.prop(gs, "eye_separation")
# layout.label(text="To do: Eye Separation") # to be done after 2.5alpha0 is out
# dome: # dome:
elif stereo_mode == 'DOME': elif stereo_mode == 'DOME':

View File

@@ -264,6 +264,7 @@ class PHYSICS_PT_softbody_solver(PhysicButtonsPanel):
layout.label(text="Diagnostics:") layout.label(text="Diagnostics:")
layout.prop(softbody, "diagnose") layout.prop(softbody, "diagnose")
layout.prop(softbody, "estimate_matrix")
class PHYSICS_PT_softbody_field_weights(PhysicButtonsPanel): class PHYSICS_PT_softbody_field_weights(PhysicButtonsPanel):

View File

@@ -581,8 +581,42 @@ class RENDER_PT_stamp(RenderButtonsPanel):
sub.prop(rd, "stamp_note_text", text="") sub.prop(rd, "stamp_note_text", text="")
bpy.types.register(RENDER_MT_presets) class RENDER_PT_bake(RenderButtonsPanel):
bl_label = "Bake"
bl_default_closed = True
COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
rd = context.scene.render_data
wide_ui = context.region.width > narrowui
row = layout.row()
row.operator("object.bake_image", icon='RENDER_STILL')
row.prop(rd, "bake_type", text="")
col = layout.column()
col.active = (rd.bake_type == 'NORMALS')
col.prop(rd, "bake_normal_space")
# col.prop(rd, "bake_aa_mode")
# col.prop(rd, "bake_enable_aa")
col = layout.column()
row = col.row(align=True)
row.prop(rd, "bake_active")
row.prop(rd, "bake_normalized")
row = col.row(align=True)
row.prop(rd, "bake_clear")
row.prop(rd, "bake_margin")
row = col.row(align=True)
row.prop(rd, "bake_distance")
row.prop(rd, "bake_bias")
bpy.types.register(RENDER_MT_presets)
bpy.types.register(RENDER_PT_render) bpy.types.register(RENDER_PT_render)
bpy.types.register(RENDER_PT_layers) bpy.types.register(RENDER_PT_layers)
bpy.types.register(RENDER_PT_dimensions) bpy.types.register(RENDER_PT_dimensions)
@@ -593,3 +627,4 @@ bpy.types.register(RENDER_PT_encoding)
bpy.types.register(RENDER_PT_performance) bpy.types.register(RENDER_PT_performance)
bpy.types.register(RENDER_PT_post_processing) bpy.types.register(RENDER_PT_post_processing)
bpy.types.register(RENDER_PT_stamp) bpy.types.register(RENDER_PT_stamp)
bpy.types.register(RENDER_PT_bake)

View File

@@ -131,7 +131,7 @@ class ConsoleExec(bpy.types.Operator):
return execute(context) return execute(context)
else: else:
print("Error: bpy.ops.console.execute_" + sc.language + " - not found") print("Error: bpy.ops.console.execute_" + sc.language + " - not found")
return ('FINISHED',) return {'FINISHED'}
class ConsoleAutocomplete(bpy.types.Operator): class ConsoleAutocomplete(bpy.types.Operator):
@@ -153,11 +153,13 @@ class ConsoleAutocomplete(bpy.types.Operator):
return autocomplete(context) return autocomplete(context)
else: else:
print("Error: bpy.ops.console.autocomplete_" + sc.language + " - not found") print("Error: bpy.ops.console.autocomplete_" + sc.language + " - not found")
return ('FINISHED',) return {'FINISHED'}
class ConsoleBanner(bpy.types.Operator): class ConsoleBanner(bpy.types.Operator):
'''Print a message whem the terminal initializes'''
bl_idname = "console.banner" bl_idname = "console.banner"
bl_label = "Console Banner"
def execute(self, context): def execute(self, context):
sc = context.space_data sc = context.space_data
@@ -173,12 +175,13 @@ class ConsoleBanner(bpy.types.Operator):
return banner(context) return banner(context)
else: else:
print("Error: bpy.ops.console.banner_" + sc.language + " - not found") print("Error: bpy.ops.console.banner_" + sc.language + " - not found")
return ('FINISHED',) return {'FINISHED'}
class ConsoleLanguage(bpy.types.Operator): class ConsoleLanguage(bpy.types.Operator):
'''Set the current language for this console''' '''Set the current language for this console'''
bl_idname = "console.language" bl_idname = "console.language"
bl_label = "Console Language"
language = StringProperty(name="Language", maxlen=32, default="") language = StringProperty(name="Language", maxlen=32, default="")
def execute(self, context): def execute(self, context):
@@ -193,7 +196,7 @@ class ConsoleLanguage(bpy.types.Operator):
bpy.ops.console.history_append(text="", current_character=0, bpy.ops.console.history_append(text="", current_character=0,
remove_duplicates=True) remove_duplicates=True)
return ('FINISHED',) return {'FINISHED'}
bpy.types.register(CONSOLE_HT_header) bpy.types.register(CONSOLE_HT_header)
@@ -202,9 +205,9 @@ bpy.types.register(CONSOLE_MT_report)
bpy.types.register(CONSOLE_MT_language) bpy.types.register(CONSOLE_MT_language)
# Stubs that call the language operators # Stubs that call the language operators
bpy.ops.add(ConsoleExec) bpy.types.register(ConsoleExec)
bpy.ops.add(ConsoleAutocomplete) bpy.types.register(ConsoleAutocomplete)
bpy.ops.add(ConsoleBanner) bpy.types.register(ConsoleBanner)
# Set the language and call the banner # Set the language and call the banner
bpy.ops.add(ConsoleLanguage) bpy.types.register(ConsoleLanguage)

View File

@@ -19,9 +19,6 @@
# <pep8 compliant> # <pep8 compliant>
import bpy import bpy
import dynamic_menu
# reload(dynamic_menu)
class INFO_HT_header(bpy.types.Header): class INFO_HT_header(bpy.types.Header):
bl_space_type = 'INFO' bl_space_type = 'INFO'
@@ -79,7 +76,7 @@ class INFO_MT_file(bpy.types.Menu):
layout.operator("wm.read_homefile", text="New", icon='NEW') layout.operator("wm.read_homefile", text="New", icon='NEW')
layout.operator_context = 'INVOKE_AREA' layout.operator_context = 'INVOKE_AREA'
layout.operator("wm.open_mainfile", text="Open...", icon='FILE_FOLDER') layout.operator("wm.open_mainfile", text="Open...", icon='FILE_FOLDER')
layout.operator_menu_enum("wm.open_recentfile", "file", text="Open Recent") layout.menu("INFO_MT_file_open_recent")
layout.operator("wm.recover_last_session") layout.operator("wm.recover_last_session")
layout.operator("wm.recover_auto_save", text="Recover Auto Save...") layout.operator("wm.recover_auto_save", text="Recover Auto Save...")
@@ -115,21 +112,22 @@ class INFO_MT_file(bpy.types.Menu):
layout.operator_context = 'EXEC_AREA' layout.operator_context = 'EXEC_AREA'
layout.operator("wm.exit_blender", text="Quit", icon='QUIT') layout.operator("wm.exit_blender", text="Quit", icon='QUIT')
# test for expanding menus
''' class INFO_MT_file_open_recent(bpy.types.Menu):
class INFO_MT_file_more(INFO_MT_file): bl_idname = "INFO_MT_file_open_recent"
bl_label = "File" bl_label = "Open Recent..."
def draw(self, context): def draw(self, context):
import os
layout = self.layout layout = self.layout
layout.operator_context = 'EXEC_AREA'
file = open(os.path.join(bpy.home, ".Blog"), "rU")
for line in file:
line = line.rstrip()
layout.operator("wm.open_mainfile", text=line, icon='FILE_BLEND').path = line
file.close()
layout.operator("wm.read_homefile", text="TESTING ") class INFO_MT_file_import(bpy.types.Menu):
dynamic_menu.setup(INFO_MT_file_more)
'''
class INFO_MT_file_import(dynamic_menu.DynMenu):
bl_idname = "INFO_MT_file_import" bl_idname = "INFO_MT_file_import"
bl_label = "Import" bl_label = "Import"
@@ -138,7 +136,7 @@ class INFO_MT_file_import(dynamic_menu.DynMenu):
self.layout.operator("wm.collada_import", text="COLLADA (.dae)...") self.layout.operator("wm.collada_import", text="COLLADA (.dae)...")
class INFO_MT_file_export(dynamic_menu.DynMenu): class INFO_MT_file_export(bpy.types.Menu):
bl_idname = "INFO_MT_file_export" bl_idname = "INFO_MT_file_export"
bl_label = "Export" bl_label = "Export"
@@ -164,9 +162,9 @@ class INFO_MT_file_external_data(bpy.types.Menu):
layout.operator("file.find_missing_files") layout.operator("file.find_missing_files")
class INFO_MT_mesh_add(dynamic_menu.DynMenu): class INFO_MT_mesh_add(bpy.types.Menu):
bl_idname = "INFO_MT_mesh_add" bl_idname = "INFO_MT_mesh_add"
bl_label = "Mesh" bl_label = "Add Mesh"
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
@@ -183,7 +181,7 @@ class INFO_MT_mesh_add(dynamic_menu.DynMenu):
layout.operator("mesh.primitive_monkey_add", icon='MESH_MONKEY', text="Monkey") layout.operator("mesh.primitive_monkey_add", icon='MESH_MONKEY', text="Monkey")
class INFO_MT_armature_add(dynamic_menu.DynMenu): class INFO_MT_armature_add(bpy.types.Menu):
bl_idname = "INFO_MT_armature_add" bl_idname = "INFO_MT_armature_add"
bl_label = "Armature" bl_label = "Armature"
@@ -290,6 +288,7 @@ class INFO_MT_help(bpy.types.Menu):
bpy.types.register(INFO_HT_header) bpy.types.register(INFO_HT_header)
bpy.types.register(INFO_MT_file) bpy.types.register(INFO_MT_file)
bpy.types.register(INFO_MT_file_open_recent)
bpy.types.register(INFO_MT_file_import) bpy.types.register(INFO_MT_file_import)
bpy.types.register(INFO_MT_file_export) bpy.types.register(INFO_MT_file_export)
bpy.types.register(INFO_MT_file_external_data) bpy.types.register(INFO_MT_file_external_data)
@@ -308,7 +307,7 @@ class HelpOperator(bpy.types.Operator):
def execute(self, context): def execute(self, context):
import webbrowser import webbrowser
webbrowser.open(self._url) webbrowser.open(self._url)
return ('FINISHED',) return {'FINISHED'}
class HELP_OT_manual(HelpOperator): class HELP_OT_manual(HelpOperator):
@@ -391,14 +390,14 @@ class HELP_OT_operator_cheat_sheet(bpy.types.Operator):
textblock.write('\n'.join(op_strings)) textblock.write('\n'.join(op_strings))
textblock.name = "OperatorList.txt" textblock.name = "OperatorList.txt"
print("See OperatorList.txt textblock") print("See OperatorList.txt textblock")
return ('FINISHED',) return {'FINISHED'}
bpy.ops.add(HELP_OT_manual) bpy.types.register(HELP_OT_manual)
bpy.ops.add(HELP_OT_release_logs) bpy.types.register(HELP_OT_release_logs)
bpy.ops.add(HELP_OT_blender_website) bpy.types.register(HELP_OT_blender_website)
bpy.ops.add(HELP_OT_blender_eshop) bpy.types.register(HELP_OT_blender_eshop)
bpy.ops.add(HELP_OT_developer_community) bpy.types.register(HELP_OT_developer_community)
bpy.ops.add(HELP_OT_user_community) bpy.types.register(HELP_OT_user_community)
bpy.ops.add(HELP_OT_report_bug) bpy.types.register(HELP_OT_report_bug)
bpy.ops.add(HELP_OT_python_api) bpy.types.register(HELP_OT_python_api)
bpy.ops.add(HELP_OT_operator_cheat_sheet) bpy.types.register(HELP_OT_operator_cheat_sheet)

View File

@@ -102,6 +102,7 @@ class TIME_MT_view(bpy.types.Menu):
layout.operator("marker.camera_bind") layout.operator("marker.camera_bind")
class TIME_MT_frame(bpy.types.Menu): class TIME_MT_frame(bpy.types.Menu):
bl_label = "Frame" bl_label = "Frame"

View File

@@ -21,71 +21,79 @@ import bpy
KM_HIERARCHY = [ KM_HIERARCHY = [
('Window', 'EMPTY', 'WINDOW', []), # file save, window change, exit ('Window', 'EMPTY', 'WINDOW', []), # file save, window change, exit
('Screen Editing', 'EMPTY', 'WINDOW', []), # resizing, action corners ('Screen', 'EMPTY', 'WINDOW', [ # full screen, undo, screenshot
('Screen', 'EMPTY', 'WINDOW', []), # full screen, undo, screenshot ('Screen Editing', 'EMPTY', 'WINDOW', []), # resizing, action corners
]),
('View2D', 'EMPTY', 'WINDOW', []), # view 2d navigation (per region) ('View2D', 'EMPTY', 'WINDOW', []), # view 2d navigation (per region)
('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region) ('View2D Buttons List', 'EMPTY', 'WINDOW', []), # view 2d with buttons navigation
('Header', 'EMPTY', 'WINDOW', []), # header stuff (per region) ('Header', 'EMPTY', 'WINDOW', []), # header stuff (per region)
('Markers', 'EMPTY', 'WINDOW', []), # markers (per region)
('Animation', 'EMPTY', 'WINDOW', []), # frame change on click, preview range (per region)
('Grease Pencil', 'EMPTY', 'WINDOW', []), # grease pencil stuff (per region) ('Grease Pencil', 'EMPTY', 'WINDOW', []), # grease pencil stuff (per region)
('View2D Buttons List', 'EMPTY', 'WINDOW', []), # view 2d with buttons navigation ('3D View', 'VIEW_3D', 'WINDOW', [ # view 3d navigation and generic stuff (select, transform)
('Animation_Channels', 'EMPTY', 'WINDOW', []),
('Buttons Generic', 'PROPERTIES', 'WINDOW', []), # align context menu
('TimeLine', 'TIMELINE', 'WINDOW', []),
('Outliner', 'OUTLINER', 'WINDOW', []),
('View3D', 'VIEW_3D', 'WINDOW', [ # view 3d navigation and generic stuff (select, transform)
('Pose', 'EMPTY', 'WINDOW', []),
('Object Mode', 'EMPTY', 'WINDOW', []), ('Object Mode', 'EMPTY', 'WINDOW', []),
('Vertex Paint', 'EMPTY', 'WINDOW', []), ('Mesh', 'EMPTY', 'WINDOW', []),
('Weight Paint', 'EMPTY', 'WINDOW', []),
('Face Mask', 'EMPTY', 'WINDOW', []),
('Sculpt', 'EMPTY', 'WINDOW', []),
('EditMesh', 'EMPTY', 'WINDOW', []),
('Curve', 'EMPTY', 'WINDOW', []), ('Curve', 'EMPTY', 'WINDOW', []),
('Armature', 'EMPTY', 'WINDOW', []), ('Armature', 'EMPTY', 'WINDOW', []),
('Metaball', 'EMPTY', 'WINDOW', []), ('Metaball', 'EMPTY', 'WINDOW', []),
('Lattice', 'EMPTY', 'WINDOW', []), ('Lattice', 'EMPTY', 'WINDOW', []),
('Armature_Sketch', 'EMPTY', 'WINDOW', []),
('Particle', 'EMPTY', 'WINDOW', []),
('Font', 'EMPTY', 'WINDOW', []), ('Font', 'EMPTY', 'WINDOW', []),
('Object Non-modal', 'EMPTY', 'WINDOW', []), # mode change
('Pose', 'EMPTY', 'WINDOW', []),
('Vertex Paint', 'EMPTY', 'WINDOW', []),
('Weight Paint', 'EMPTY', 'WINDOW', []),
('Face Mask', 'EMPTY', 'WINDOW', []),
('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d ('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d
('View3D Generic', 'VIEW_3D', 'WINDOW', []) # toolbar and properties ('Sculpt', 'EMPTY', 'WINDOW', []),
('Armature Sketch', 'EMPTY', 'WINDOW', []),
('Particle', 'EMPTY', 'WINDOW', []),
('Object Non-modal', 'EMPTY', 'WINDOW', []), # mode change
('3D View Generic', 'VIEW_3D', 'WINDOW', []) # toolbar and properties
]), ]),
('GraphEdit Keys', 'GRAPH_EDITOR', 'WINDOW', [
('GraphEdit Generic', 'GRAPH_EDITOR', 'WINDOW', []) ('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region)
('Markers', 'EMPTY', 'WINDOW', []), # markers (per region)
('Animation', 'EMPTY', 'WINDOW', []), # frame change on click, preview range (per region)
('Animation Channels', 'EMPTY', 'WINDOW', []),
('Graph Editor', 'GRAPH_EDITOR', 'WINDOW', [
('Graph Editor Generic', 'GRAPH_EDITOR', 'WINDOW', [])
]),
('Dopesheet', 'DOPESHEET_EDITOR', 'WINDOW', []),
('NLA Editor', 'NLA_EDITOR', 'WINDOW', [
('NLA Channels', 'NLA_EDITOR', 'WINDOW', []),
('NLA Generic', 'NLA_EDITOR', 'WINDOW', [])
]), ]),
('Image', 'IMAGE_EDITOR', 'WINDOW', [ ('Image', 'IMAGE_EDITOR', 'WINDOW', [
('UVEdit', 'EMPTY', 'WINDOW', []), # image (reverse order, UVEdit before Image ('UV Editor', 'EMPTY', 'WINDOW', []), # image (reverse order, UVEdit before Image
('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d ('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d
('Image Generic', 'IMAGE_EDITOR', 'WINDOW', []) ('Image Generic', 'IMAGE_EDITOR', 'WINDOW', [])
]), ]),
('Node Generic', 'NODE_EDITOR', 'WINDOW', [ ('Timeline', 'TIMELINE', 'WINDOW', []),
('Node', 'NODE_EDITOR', 'WINDOW', []) ('Outliner', 'OUTLINER', 'WINDOW', []),
('Node Editor', 'NODE_EDITOR', 'WINDOW', [
('Node Generic', 'NODE_EDITOR', 'WINDOW', [])
]), ]),
('File', 'FILE_BROWSER', 'WINDOW', [ ('Sequencer', 'SEQUENCE_EDITOR', 'WINDOW', []),
('FileMain', 'FILE_BROWSER', 'WINDOW', []), ('Logic Editor', 'LOGIC_EDITOR', 'WINDOW', []),
('FileButtons', 'FILE_BROWSER', 'WINDOW', [])
]), ('File Browser', 'FILE_BROWSER', 'WINDOW', [
('Action_Keys', 'DOPESHEET_EDITOR', 'WINDOW', []), ('File Browser Main', 'FILE_BROWSER', 'WINDOW', []),
('NLA Generic', 'NLA_EDITOR', 'WINDOW', [ ('File Browser Buttons', 'FILE_BROWSER', 'WINDOW', [])
('NLA Channels', 'NLA_EDITOR', 'WINDOW', []),
('NLA Data', 'NLA_EDITOR', 'WINDOW', [])
]), ]),
('Property Editor', 'PROPERTIES', 'WINDOW', []), # align context menu
('Script', 'SCRIPTS_WINDOW', 'WINDOW', []), ('Script', 'SCRIPTS_WINDOW', 'WINDOW', []),
('Text', 'TEXT_EDITOR', 'WINDOW', []), ('Text', 'TEXT_EDITOR', 'WINDOW', []),
('Sequencer', 'SEQUENCE_EDITOR', 'WINDOW', []),
('Logic Generic', 'LOGIC_EDITOR', 'WINDOW', []),
('Console', 'CONSOLE', 'WINDOW', []), ('Console', 'CONSOLE', 'WINDOW', []),
('View3D Gesture Circle', 'EMPTY', 'WINDOW', []), ('View3D Gesture Circle', 'EMPTY', 'WINDOW', []),
('Gesture Border', 'EMPTY', 'WINDOW', []), ('Gesture Border', 'EMPTY', 'WINDOW', []),
('Standard Modal Map', 'EMPTY', 'WINDOW', []), ('Standard Modal Map', 'EMPTY', 'WINDOW', []),
@@ -503,8 +511,6 @@ class USERPREF_PT_system(bpy.types.Panel):
sub.template_color_ramp(system, "weight_color_range", expand=True) sub.template_color_ramp(system, "weight_color_range", expand=True)
class USERPREF_PT_theme(bpy.types.Panel): class USERPREF_PT_theme(bpy.types.Panel):
bl_space_type = 'USER_PREFERENCES' bl_space_type = 'USER_PREFERENCES'
bl_label = "Themes" bl_label = "Themes"
@@ -1254,10 +1260,10 @@ class USERPREF_PT_input(bpy.types.Panel):
userpref = context.user_preferences userpref = context.user_preferences
return (userpref.active_section == 'INPUT') return (userpref.active_section == 'INPUT')
def draw_entry(self, kc, entry, col, level = 0): def draw_entry(self, kc, entry, col, level=0):
idname, spaceid, regionid, children = entry idname, spaceid, regionid, children = entry
km = kc.find_keymap(idname, space_type = spaceid, region_type = regionid) km = kc.find_keymap(idname, space_type=spaceid, region_type=regionid)
if km: if km:
self.draw_km(kc, km, children, col, level) self.draw_km(kc, km, children, col, level)
@@ -1266,9 +1272,9 @@ class USERPREF_PT_input(bpy.types.Panel):
indentpx = 16 indentpx = 16
if level == 0: if level == 0:
level = 0.0001 # Tweak so that a percentage of 0 won't split by half level = 0.0001 # Tweak so that a percentage of 0 won't split by half
indent = level*indentpx / bpy.context.region.width indent = level * indentpx / bpy.context.region.width
split=layout.split(percentage=indent) split = layout.split(percentage=indent)
col = split.column() col = split.column()
col = split.column() col = split.column()
return col return col
@@ -1309,7 +1315,7 @@ class USERPREF_PT_input(bpy.types.Panel):
self.draw_kmi(kc, km, kmi, col, level + 1) self.draw_kmi(kc, km, kmi, col, level + 1)
# "Add New" at end of keymap item list # "Add New" at end of keymap item list
col = self.indented_layout(col, level+1) col = self.indented_layout(col, level + 1)
subcol = col.split(percentage=0.2).column() subcol = col.split(percentage=0.2).column()
subcol.active = km.user_defined subcol.active = km.user_defined
subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN') subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN')
@@ -1324,7 +1330,6 @@ class USERPREF_PT_input(bpy.types.Panel):
for entry in children: for entry in children:
self.draw_entry(kc, entry, col, level + 1) self.draw_entry(kc, entry, col, level + 1)
def draw_kmi(self, kc, km, kmi, layout, level): def draw_kmi(self, kc, km, kmi, layout, level):
layout.set_context_pointer("keyitem", kmi) layout.set_context_pointer("keyitem", kmi)
@@ -1475,8 +1480,9 @@ class USERPREF_PT_input(bpy.types.Panel):
if len(filtered_items) != 0: if len(filtered_items) != 0:
km = km.active() km = km.active()
layout.set_context_pointer("keymap", km)
col = layout.column() col = layout.column()
col.set_context_pointer("keymap", km)
row = col.row() row = col.row()
row.label(text=km.name, icon="DOT") row.label(text=km.name, icon="DOT")
@@ -1491,6 +1497,12 @@ class USERPREF_PT_input(bpy.types.Panel):
for kmi in filtered_items: for kmi in filtered_items:
self.draw_kmi(kc, km, kmi, col, 1) self.draw_kmi(kc, km, kmi, col, 1)
# "Add New" at end of keymap item list
col = self.indented_layout(layout, 1)
subcol = col.split(percentage=0.2).column()
subcol.active = km.user_defined
subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN')
def draw_hierarchy(self, defkc, layout): def draw_hierarchy(self, defkc, layout):
for entry in KM_HIERARCHY: for entry in KM_HIERARCHY:
self.draw_entry(defkc, entry, layout) self.draw_entry(defkc, entry, layout)
@@ -1540,13 +1552,15 @@ bpy.types.register(USERPREF_PT_input)
from bpy.props import * from bpy.props import *
class WM_OT_keyconfig_test(bpy.types.Operator): class WM_OT_keyconfig_test(bpy.types.Operator):
"Test keyconfig for conflicts." "Test keyconfig for conflicts."
bl_idname = "wm.keyconfig_test" bl_idname = "wm.keyconfig_test"
bl_label = "Test Key Configuration for Conflicts" bl_label = "Test Key Configuration for Conflicts"
def testEntry(self, kc, entry, src = None, parent = None): def testEntry(self, kc, entry, src=None, parent=None):
result = False result = False
def kmistr(kmi): def kmistr(kmi):
if km.modal: if km.modal:
s = ["kmi = km.add_modal_item(\'%s\', \'%s\', \'%s\'" % (kmi.propvalue, kmi.type, kmi.value)] s = ["kmi = km.add_modal_item(\'%s\', \'%s\', \'%s\'" % (kmi.propvalue, kmi.type, kmi.value)]
@@ -1566,9 +1580,9 @@ class WM_OT_keyconfig_test(bpy.types.Operator):
s.append(", oskey=True") s.append(", oskey=True")
if kmi.key_modifier and kmi.key_modifier != 'NONE': if kmi.key_modifier and kmi.key_modifier != 'NONE':
s.append(", key_modifier=\'%s\'" % kmi.key_modifier) s.append(", key_modifier=\'%s\'" % kmi.key_modifier)
s.append(")\n") s.append(")\n")
props = kmi.properties props = kmi.properties
if props is not None: if props is not None:
@@ -1578,16 +1592,16 @@ class WM_OT_keyconfig_test(bpy.types.Operator):
value = _string_value(value) value = _string_value(value)
if value != "": if value != "":
s.append("kmi.properties.%s = %s\n" % (pname, value)) s.append("kmi.properties.%s = %s\n" % (pname, value))
return "".join(s).strip() return "".join(s).strip()
idname, spaceid, regionid, children = entry idname, spaceid, regionid, children = entry
km = kc.find_keymap(idname, space_type = spaceid, region_type = regionid) km = kc.find_keymap(idname, space_type=spaceid, region_type=regionid)
if km: if km:
km = km.active() km = km.active()
if src: if src:
for item in km.items: for item in km.items:
if src.compare(item): if src.compare(item):
@@ -1597,14 +1611,14 @@ class WM_OT_keyconfig_test(bpy.types.Operator):
print(km.name) print(km.name)
print(kmistr(item)) print(kmistr(item))
result = True result = True
for child in children: for child in children:
if self.testEntry(kc, child, src, parent): if self.testEntry(kc, child, src, parent):
result = True result = True
else: else:
for i in range(len(km.items)): for i in range(len(km.items)):
src = km.items[i] src = km.items[i]
for child in children: for child in children:
if self.testEntry(kc, child, src, km): if self.testEntry(kc, child, src, km):
result = True result = True
@@ -1617,28 +1631,29 @@ class WM_OT_keyconfig_test(bpy.types.Operator):
print(kmistr(src)) print(kmistr(src))
print(kmistr(item)) print(kmistr(item))
result = True result = True
for child in children: for child in children:
if self.testEntry(kc, child): if self.testEntry(kc, child):
result = True result = True
return result return result
def testConfig(self, kc): def testConfig(self, kc):
result = False result = False
for entry in KM_HIERARCHY: for entry in KM_HIERARCHY:
if self.testEntry(kc, entry): if self.testEntry(kc, entry):
result = True result = True
return result return result
def execute(self, context): def execute(self, context):
wm = context.manager wm = context.manager
kc = wm.default_keyconfig kc = wm.default_keyconfig
if self.testConfig(kc): if self.testConfig(kc):
print("CONFLICT") print("CONFLICT")
return ('FINISHED',) return {'FINISHED'}
def _string_value(value): def _string_value(value):
result = "" result = ""
@@ -1666,7 +1681,8 @@ def _string_value(value):
print("Export key configuration: can't write ", value) print("Export key configuration: can't write ", value)
return result return result
class WM_OT_keyconfig_export(bpy.types.Operator): class WM_OT_keyconfig_export(bpy.types.Operator):
"Export key configuration to a python script." "Export key configuration to a python script."
bl_idname = "wm.keyconfig_export" bl_idname = "wm.keyconfig_export"
@@ -1728,12 +1744,12 @@ class WM_OT_keyconfig_export(bpy.types.Operator):
f.close() f.close()
return ('FINISHED',) return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
wm = context.manager wm = context.manager
wm.add_fileselect(self) wm.add_fileselect(self)
return ('RUNNING_MODAL',) return {'RUNNING_MODAL'}
class WM_OT_keymap_edit(bpy.types.Operator): class WM_OT_keymap_edit(bpy.types.Operator):
@@ -1745,7 +1761,7 @@ class WM_OT_keymap_edit(bpy.types.Operator):
wm = context.manager wm = context.manager
km = context.keymap km = context.keymap
km.copy_to_user() km.copy_to_user()
return ('FINISHED',) return {'FINISHED'}
class WM_OT_keymap_restore(bpy.types.Operator): class WM_OT_keymap_restore(bpy.types.Operator):
@@ -1765,7 +1781,8 @@ class WM_OT_keymap_restore(bpy.types.Operator):
km = context.keymap km = context.keymap
km.restore_to_default() km.restore_to_default()
return ('FINISHED',) return {'FINISHED'}
class WM_OT_keyitem_restore(bpy.types.Operator): class WM_OT_keyitem_restore(bpy.types.Operator):
"Restore key map item." "Restore key map item."
@@ -1784,8 +1801,9 @@ class WM_OT_keyitem_restore(bpy.types.Operator):
km.restore_item_to_default(kmi) km.restore_item_to_default(kmi)
return ('FINISHED',) return {'FINISHED'}
class WM_OT_keyitem_add(bpy.types.Operator): class WM_OT_keyitem_add(bpy.types.Operator):
"Add key map item." "Add key map item."
bl_idname = "wm.keyitem_add" bl_idname = "wm.keyitem_add"
@@ -1794,11 +1812,20 @@ class WM_OT_keyitem_add(bpy.types.Operator):
def execute(self, context): def execute(self, context):
wm = context.manager wm = context.manager
km = context.keymap km = context.keymap
kc = wm.default_keyconfig
if km.modal: if km.modal:
km.add_modal_item("", 'A', 'PRESS') # kmi km.add_modal_item("", 'A', 'PRESS') # kmi
else: else:
km.add_item("", 'A', 'PRESS') # kmi km.add_item("none", 'A', 'PRESS') # kmi
return ('FINISHED',)
# clear filter and expand keymap so we can see the newly added item
if kc.filter != '':
kc.filter = ''
km.items_expanded = True
km.children_expanded = True
return {'FINISHED'}
class WM_OT_keyitem_remove(bpy.types.Operator): class WM_OT_keyitem_remove(bpy.types.Operator):
@@ -1811,12 +1838,12 @@ class WM_OT_keyitem_remove(bpy.types.Operator):
kmi = context.keyitem kmi = context.keyitem
km = context.keymap km = context.keymap
km.remove_item(kmi) km.remove_item(kmi)
return ('FINISHED',) return {'FINISHED'}
bpy.ops.add(WM_OT_keyconfig_export) bpy.types.register(WM_OT_keyconfig_export)
bpy.ops.add(WM_OT_keyconfig_test) bpy.types.register(WM_OT_keyconfig_test)
bpy.ops.add(WM_OT_keymap_edit) bpy.types.register(WM_OT_keymap_edit)
bpy.ops.add(WM_OT_keymap_restore) bpy.types.register(WM_OT_keymap_restore)
bpy.ops.add(WM_OT_keyitem_add) bpy.types.register(WM_OT_keyitem_add)
bpy.ops.add(WM_OT_keyitem_remove) bpy.types.register(WM_OT_keyitem_remove)
bpy.ops.add(WM_OT_keyitem_restore) bpy.types.register(WM_OT_keyitem_restore)

View File

@@ -18,7 +18,6 @@
# <pep8 compliant> # <pep8 compliant>
import bpy import bpy
import dynamic_menu
class VIEW3D_HT_header(bpy.types.Header): class VIEW3D_HT_header(bpy.types.Header):
@@ -205,7 +204,7 @@ class VIEW3D_MT_snap(bpy.types.Menu):
layout.operator("view3d.snap_cursor_to_active", text="Cursor to Active") layout.operator("view3d.snap_cursor_to_active", text="Cursor to Active")
class VIEW3D_MT_uv_map(dynamic_menu.DynMenu): class VIEW3D_MT_uv_map(bpy.types.Menu):
bl_label = "UV Mapping" bl_label = "UV Mapping"
def draw(self, context): def draw(self, context):
@@ -456,6 +455,7 @@ class VIEW3D_MT_select_edit_mesh(bpy.types.Menu):
layout.separator() layout.separator()
layout.operator("mesh.select_random", text="Random...") layout.operator("mesh.select_random", text="Random...")
layout.operator("mesh.select_nth", text="Select Nth...")
layout.operator("mesh.edges_select_sharp", text="Sharp Edges") layout.operator("mesh.edges_select_sharp", text="Sharp Edges")
layout.operator("mesh.faces_select_linked_flat", text="Linked Flat Faces") layout.operator("mesh.faces_select_linked_flat", text="Linked Flat Faces")
layout.operator("mesh.faces_select_interior", text="Interior Faces") layout.operator("mesh.faces_select_interior", text="Interior Faces")
@@ -902,6 +902,24 @@ class VIEW3D_MT_particle(bpy.types.Menu):
layout.menu("VIEW3D_MT_particle_showhide") layout.menu("VIEW3D_MT_particle_showhide")
class VIEW3D_MT_particle_specials(bpy.types.Menu):
bl_label = "Specials"
def draw(self, context):
layout = self.layout
particle_edit = context.tool_settings.particle_edit
layout.operator("particle.rekey")
layout.separator()
if particle_edit.selection_mode == 'POINT':
layout.operator("particle.subdivide")
layout.operator("particle.select_first")
layout.operator("particle.select_last")
layout.operator("particle.remove_doubles")
class VIEW3D_MT_particle_showhide(VIEW3D_MT_showhide): class VIEW3D_MT_particle_showhide(VIEW3D_MT_showhide):
_operator_name = "particle" _operator_name = "particle"
@@ -1121,6 +1139,27 @@ class VIEW3D_MT_edit_mesh_specials(bpy.types.Menu):
layout.operator("mesh.select_vertex_path") layout.operator("mesh.select_vertex_path")
class VIEW3D_MT_edit_mesh_selection_mode(bpy.types.Menu):
bl_label = "Mesh Select Mode"
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
prop = layout.operator("wm.context_set_value", text="Vertex", icon='VERTEXSEL')
prop.value = "(True, False, False)"
prop.path = "tool_settings.mesh_selection_mode"
prop = layout.operator("wm.context_set_value", text="Edge", icon='EDGESEL')
prop.value = "(False, True, False)"
prop.path = "tool_settings.mesh_selection_mode"
prop = layout.operator("wm.context_set_value", text="Face", icon='FACESEL')
prop.value = "(False, False, True)"
prop.path = "tool_settings.mesh_selection_mode"
class VIEW3D_MT_edit_mesh_vertices(bpy.types.Menu): class VIEW3D_MT_edit_mesh_vertices(bpy.types.Menu):
bl_label = "Vertices" bl_label = "Vertices"
@@ -1190,7 +1229,7 @@ class VIEW3D_MT_edit_mesh_edges(bpy.types.Menu):
layout.operator("mesh.region_to_loop") layout.operator("mesh.region_to_loop")
class VIEW3D_MT_edit_mesh_faces(dynamic_menu.DynMenu): class VIEW3D_MT_edit_mesh_faces(bpy.types.Menu):
bl_label = "Faces" bl_label = "Faces"
bl_idname = "VIEW3D_MT_edit_mesh_faces" bl_idname = "VIEW3D_MT_edit_mesh_faces"
@@ -1323,6 +1362,20 @@ class VIEW3D_MT_edit_curve_segments(bpy.types.Menu):
layout.operator("curve.switch_direction") layout.operator("curve.switch_direction")
class VIEW3D_MT_edit_curve_specials(bpy.types.Menu):
bl_label = "Specials"
def draw(self, context):
layout = self.layout
layout.operator("curve.subdivide")
layout.operator("curve.switch_direction")
layout.operator("curve.spline_weight_set")
layout.operator("curve.radius_set")
layout.operator("curve.smooth")
layout.operator("curve.smooth_radius")
class VIEW3D_MT_edit_curve_showhide(VIEW3D_MT_showhide): class VIEW3D_MT_edit_curve_showhide(VIEW3D_MT_showhide):
_operator_name = "curve" _operator_name = "curve"
@@ -1901,7 +1954,8 @@ bpy.types.register(VIEW3D_MT_sculpt) # Sculpt Menu
bpy.types.register(VIEW3D_MT_paint_vertex) bpy.types.register(VIEW3D_MT_paint_vertex)
bpy.types.register(VIEW3D_MT_particle) # Particle Menu bpy.types.register(VIEW3D_MT_particle)# Particle Menu
bpy.types.register(VIEW3D_MT_particle_specials)
bpy.types.register(VIEW3D_MT_particle_showhide) bpy.types.register(VIEW3D_MT_particle_showhide)
bpy.types.register(VIEW3D_MT_pose) # POSE Menu bpy.types.register(VIEW3D_MT_pose) # POSE Menu
@@ -1915,6 +1969,7 @@ bpy.types.register(VIEW3D_MT_pose_showhide)
bpy.types.register(VIEW3D_MT_edit_mesh) bpy.types.register(VIEW3D_MT_edit_mesh)
bpy.types.register(VIEW3D_MT_edit_mesh_specials) # Only as a menu for keybindings bpy.types.register(VIEW3D_MT_edit_mesh_specials) # Only as a menu for keybindings
bpy.types.register(VIEW3D_MT_edit_mesh_selection_mode) # Only as a menu for keybindings
bpy.types.register(VIEW3D_MT_edit_mesh_vertices) bpy.types.register(VIEW3D_MT_edit_mesh_vertices)
bpy.types.register(VIEW3D_MT_edit_mesh_edges) bpy.types.register(VIEW3D_MT_edit_mesh_edges)
bpy.types.register(VIEW3D_MT_edit_mesh_faces) bpy.types.register(VIEW3D_MT_edit_mesh_faces)
@@ -1924,6 +1979,7 @@ bpy.types.register(VIEW3D_MT_edit_mesh_showhide)
bpy.types.register(VIEW3D_MT_edit_curve) bpy.types.register(VIEW3D_MT_edit_curve)
bpy.types.register(VIEW3D_MT_edit_curve_ctrlpoints) bpy.types.register(VIEW3D_MT_edit_curve_ctrlpoints)
bpy.types.register(VIEW3D_MT_edit_curve_segments) bpy.types.register(VIEW3D_MT_edit_curve_segments)
bpy.types.register(VIEW3D_MT_edit_curve_specials)
bpy.types.register(VIEW3D_MT_edit_curve_showhide) bpy.types.register(VIEW3D_MT_edit_curve_showhide)
bpy.types.register(VIEW3D_MT_edit_surface) bpy.types.register(VIEW3D_MT_edit_surface)

View File

@@ -498,7 +498,15 @@ class VIEW3D_PT_tools_brush(PaintPanel):
if not context.particle_edit_object: if not context.particle_edit_object:
col = layout.split().column() col = layout.split().column()
row = col.row() row = col.row()
row.template_list(settings, "brushes", settings, "active_brush_index", rows=2)
if context.sculpt_object and brush:
defaulttools = 8
elif context.texture_paint_object and brush:
defaulttools = 4
else:
defaulttools = 2
row.template_list(settings, "brushes", settings, "active_brush_index", rows=2, maxrows=defaulttools)
col.template_ID(settings, "brush", new="brush.add") col.template_ID(settings, "brush", new="brush.add")
@@ -531,8 +539,6 @@ class VIEW3D_PT_tools_brush(PaintPanel):
elif context.sculpt_object and brush: elif context.sculpt_object and brush:
col = layout.column() col = layout.column()
col.separator() col.separator()
col.prop(brush, "sculpt_tool", expand=True)
col.separator()
row = col.row(align=True) row = col.row(align=True)
row.prop(brush, "size", slider=True) row.prop(brush, "size", slider=True)
@@ -563,12 +569,6 @@ class VIEW3D_PT_tools_brush(PaintPanel):
# Texture Paint Mode # # Texture Paint Mode #
elif context.texture_paint_object and brush: elif context.texture_paint_object and brush:
col = layout.column(align=True)
col.prop_enum(settings, "tool", 'DRAW')
col.prop_enum(settings, "tool", 'SOFTEN')
col.prop_enum(settings, "tool", 'CLONE')
col.prop_enum(settings, "tool", 'SMEAR')
col = layout.column() col = layout.column()
col.prop(brush, "color", text="") col.prop(brush, "color", text="")
@@ -624,6 +624,33 @@ class VIEW3D_PT_tools_brush(PaintPanel):
#row.prop(brush, "jitter", slider=True) #row.prop(brush, "jitter", slider=True)
#row.prop(brush, "use_jitter_pressure", toggle=True, text="") #row.prop(brush, "use_jitter_pressure", toggle=True, text="")
class VIEW3D_PT_tools_brush_tool(PaintPanel):
bl_label = "Tool"
bl_default_closed = True
def poll(self, context):
settings = self.paint_settings(context)
return (settings and settings.brush and (context.sculpt_object or
context.texture_paint_object))
def draw(self, context):
layout = self.layout
settings = self.paint_settings(context)
brush = settings.brush
texture_paint = context.texture_paint_object
sculpt = context.sculpt_object
col = layout.column(align=True)
if context.sculpt_object:
col.prop(brush, "sculpt_tool", expand=True)
elif context.texture_paint_object:
col.prop_enum(settings, "tool", 'DRAW')
col.prop_enum(settings, "tool", 'SOFTEN')
col.prop_enum(settings, "tool", 'CLONE')
col.prop_enum(settings, "tool", 'SMEAR')
class VIEW3D_PT_tools_brush_stroke(PaintPanel): class VIEW3D_PT_tools_brush_stroke(PaintPanel):
bl_label = "Stroke" bl_label = "Stroke"
@@ -690,7 +717,7 @@ class VIEW3D_PT_sculpt_options(PaintPanel):
bl_label = "Options" bl_label = "Options"
def poll(self, context): def poll(self, context):
return context.sculpt_object return (context.sculpt_object and context.tool_settings.sculpt)
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
@@ -826,24 +853,50 @@ class VIEW3D_PT_tools_projectpaint(View3DPanel):
col.active = (ipaint.use_normal_falloff and use_projection) col.active = (ipaint.use_normal_falloff and use_projection)
col.prop(ipaint, "normal_angle", text="") col.prop(ipaint, "normal_angle", text="")
split = layout.split(percentage=0.7) col = layout.column(align=False)
row = col.row()
row.active = (use_projection)
row.prop(ipaint, "use_stencil_layer", text="Stencil")
col = split.column(align=False) row2 = row.row(align=False)
col.active = (use_projection) row2.active = (use_projection and ipaint.use_stencil_layer)
col.prop(ipaint, "use_stencil_layer") row2.menu("VIEW3D_MT_tools_projectpaint_stencil", text=context.active_object.data.uv_texture_stencil.name)
row2.prop(ipaint, "invert_stencil", text="", icon='IMAGE_ALPHA')
col = split.column(align=False)
col.active = (use_projection and ipaint.use_stencil_layer)
col.prop(ipaint, "invert_stencil", text="Inv")
col = layout.column() col = layout.column()
sub = col.column() sub = col.column()
sub.active = (settings.tool == 'CLONE') row = sub.row()
sub.prop(ipaint, "use_clone_layer") row.active = (settings.tool == 'CLONE')
row.prop(ipaint, "use_clone_layer", text="Clone")
row.menu("VIEW3D_MT_tools_projectpaint_clone", text=context.active_object.data.uv_texture_clone.name)
sub = col.column() sub = col.column()
sub.prop(ipaint, "seam_bleed") sub.prop(ipaint, "seam_bleed")
class VIEW3D_MT_tools_projectpaint_clone(bpy.types.Menu):
bl_label = "Clone Layer"
def draw(self, context):
layout = self.layout
for i, tex in enumerate(context.active_object.data.uv_textures):
prop = layout.operator("wm.context_set_int", text=tex.name)
prop.path = "active_object.data.uv_texture_clone_index"
prop.value = i
class VIEW3D_MT_tools_projectpaint_stencil(bpy.types.Menu):
bl_label = "Mask Layer"
def draw(self, context):
layout = self.layout
for i, tex in enumerate(context.active_object.data.uv_textures):
prop = layout.operator("wm.context_set_int", text=tex.name)
prop.path = "active_object.data.uv_texture_stencil_index"
prop.value = i
bpy.types.register(VIEW3D_MT_tools_projectpaint_clone)
bpy.types.register(VIEW3D_MT_tools_projectpaint_stencil)
class VIEW3D_PT_tools_particlemode(View3DPanel): class VIEW3D_PT_tools_particlemode(View3DPanel):
'''default tools for particle mode''' '''default tools for particle mode'''
@@ -922,6 +975,7 @@ bpy.types.register(VIEW3D_PT_tools_latticeedit)
bpy.types.register(VIEW3D_PT_tools_posemode) bpy.types.register(VIEW3D_PT_tools_posemode)
bpy.types.register(VIEW3D_PT_tools_posemode_options) bpy.types.register(VIEW3D_PT_tools_posemode_options)
bpy.types.register(VIEW3D_PT_tools_brush) bpy.types.register(VIEW3D_PT_tools_brush)
bpy.types.register(VIEW3D_PT_tools_brush_tool)
bpy.types.register(VIEW3D_PT_tools_brush_stroke) bpy.types.register(VIEW3D_PT_tools_brush_stroke)
bpy.types.register(VIEW3D_PT_tools_brush_curve) bpy.types.register(VIEW3D_PT_tools_brush_curve)
bpy.types.register(VIEW3D_PT_sculpt_options) bpy.types.register(VIEW3D_PT_sculpt_options)

View File

@@ -16,8 +16,6 @@
# #
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
import unittest import unittest
import random import random

View File

@@ -137,6 +137,10 @@ ifeq ($(WITH_SNDFILE),true)
COMLIB += $(NAN_AUDASPACE)/lib/$(DEBUG_DIR)libaud_sndfile.a COMLIB += $(NAN_AUDASPACE)/lib/$(DEBUG_DIR)libaud_sndfile.a
endif endif
ifeq ($(WITH_FFTW3),true)
COMLIB += $(NAN_AUDASPACE)/lib/$(DEBUG_DIR)libaud_fftw.a
endif
ifneq ($(NAN_NO_KETSJI),true) ifneq ($(NAN_NO_KETSJI),true)
COMLIB += $(OCGDIR)/gameengine/bloutines/$(DEBUG_DIR)libbloutines.a COMLIB += $(OCGDIR)/gameengine/bloutines/$(DEBUG_DIR)libbloutines.a
COMLIB += $(OCGDIR)/gameengine/blconverter/$(DEBUG_DIR)libblconverter.a COMLIB += $(OCGDIR)/gameengine/blconverter/$(DEBUG_DIR)libblconverter.a

View File

@@ -182,11 +182,11 @@ AviError AVI_print_error (AviError in_error) {
return in_error; return in_error;
} }
/*
void AVI_set_debug (int mode) { void AVI_set_debug (int mode) {
AVI_DEBUG= mode; AVI_DEBUG= mode;
} }
*/
/* /*
int AVI_is_avi (char *name) { int AVI_is_avi (char *name) {
FILE *fp; FILE *fp;

View File

@@ -198,11 +198,11 @@ int CustomData_get_named_layer_index(const struct CustomData *data, int type, ch
int CustomData_get_active_layer_index(const struct CustomData *data, int type); int CustomData_get_active_layer_index(const struct CustomData *data, int type);
int CustomData_get_render_layer_index(const struct CustomData *data, int type); int CustomData_get_render_layer_index(const struct CustomData *data, int type);
int CustomData_get_clone_layer_index(const struct CustomData *data, int type); int CustomData_get_clone_layer_index(const struct CustomData *data, int type);
int CustomData_get_mask_layer_index(const struct CustomData *data, int type); int CustomData_get_stencil_layer_index(const struct CustomData *data, int type);
int CustomData_get_active_layer(const struct CustomData *data, int type); int CustomData_get_active_layer(const struct CustomData *data, int type);
int CustomData_get_render_layer(const struct CustomData *data, int type); int CustomData_get_render_layer(const struct CustomData *data, int type);
int CustomData_get_clone_layer(const struct CustomData *data, int type); int CustomData_get_clone_layer(const struct CustomData *data, int type);
int CustomData_get_mask_layer(const struct CustomData *data, int type); int CustomData_get_stencil_layer(const struct CustomData *data, int type);
/* copies the data from source to the data element at index in the first /* copies the data from source to the data element at index in the first
* layer of type * layer of type
@@ -231,13 +231,13 @@ void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, voi
void CustomData_set_layer_active(struct CustomData *data, int type, int n); void CustomData_set_layer_active(struct CustomData *data, int type, int n);
void CustomData_set_layer_render(struct CustomData *data, int type, int n); void CustomData_set_layer_render(struct CustomData *data, int type, int n);
void CustomData_set_layer_clone(struct CustomData *data, int type, int n); void CustomData_set_layer_clone(struct CustomData *data, int type, int n);
void CustomData_set_layer_mask(struct CustomData *data, int type, int n); void CustomData_set_layer_stencil(struct CustomData *data, int type, int n);
/* same as above but works with an index from CustomData_get_layer_index */ /* same as above but works with an index from CustomData_get_layer_index */
void CustomData_set_layer_active_index(struct CustomData *data, int type, int n); void CustomData_set_layer_active_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_render_index(struct CustomData *data, int type, int n); void CustomData_set_layer_render_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_clone_index(struct CustomData *data, int type, int n); void CustomData_set_layer_clone_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_mask_index(struct CustomData *data, int type, int n); void CustomData_set_layer_stencil_index(struct CustomData *data, int type, int n);
/* adds flag to the layer flags */ /* adds flag to the layer flags */
void CustomData_set_layer_flag(struct CustomData *data, int type, int flag); void CustomData_set_layer_flag(struct CustomData *data, int type, int flag);

View File

@@ -158,7 +158,12 @@ void copy_fcurves(ListBase *dst, ListBase *src);
struct FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index); struct FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index);
/* high level function to get an fcurve from C without having the rna */ /* high level function to get an fcurve from C without having the rna */
struct FCurve *id_data_find_fcurve(ID* id, void *data, struct StructRNA *type, char *prop_name, int index); struct FCurve *id_data_find_fcurve(ID *id, void *data, struct StructRNA *type, char *prop_name, int index);
/* Get list of LinkData's containing pointers to the F-Curves which control the types of data indicated
* e.g. numMatches = list_find_data_fcurves(matches, &act->curves, "pose.bones[", "MyFancyBone");
*/
int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName);
/* Binary search algorithm for finding where to 'insert' BezTriple with given frame number. /* Binary search algorithm for finding where to 'insert' BezTriple with given frame number.
* Returns the index to insert at (data already at that index will be offset if replace is 0) * Returns the index to insert at (data already at that index will be offset if replace is 0)

View File

@@ -59,7 +59,7 @@ void key_curve_normal_weights(float t, float *data, int type);
float *do_ob_key(struct Scene *scene, struct Object *ob); float *do_ob_key(struct Scene *scene, struct Object *ob);
struct Key *ob_get_key(struct Object *ob); struct Key *ob_get_key(struct Object *ob);
struct KeyBlock *add_keyblock(struct Scene *scene, struct Key *key); struct KeyBlock *add_keyblock(struct Key *key, char *name);
struct KeyBlock *ob_get_keyblock(struct Object *ob); struct KeyBlock *ob_get_keyblock(struct Object *ob);
struct KeyBlock *ob_get_reference_keyblock(struct Object *ob); struct KeyBlock *ob_get_reference_keyblock(struct Object *ob);
struct KeyBlock *key_get_keyblock(struct Key *key, int index); struct KeyBlock *key_get_keyblock(struct Key *key, int index);
@@ -68,6 +68,14 @@ char *key_get_curValue_rnaPath(struct Key *key, struct KeyBlock *kb);
// needed for the GE // needed for the GE
void do_rel_key(int start, int end, int tot, char *basispoin, struct Key *key, struct KeyBlock *actkb, int mode); void do_rel_key(int start, int end, int tot, char *basispoin, struct Key *key, struct KeyBlock *actkb, int mode);
/* conversion functions */
void key_to_mesh(struct KeyBlock *kb, struct Mesh *me);
void mesh_to_key(struct Mesh *me, struct KeyBlock *kb);
void key_to_latt(struct KeyBlock *kb, struct Lattice *lt);
void latt_to_key(struct Lattice *lt, struct KeyBlock *kb);
void key_to_curve(struct KeyBlock *kb, struct Curve *cu, struct ListBase *nurb);
void curve_to_key(struct Curve *cu, struct KeyBlock *kb, struct ListBase *nurb);
#ifdef __cplusplus #ifdef __cplusplus
}; };
#endif #endif

View File

@@ -120,6 +120,7 @@ int give_obdata_texspace(struct Object *ob, short **texflag, float **loc, float
int object_insert_ptcache(struct Object *ob); int object_insert_ptcache(struct Object *ob);
// void object_delete_ptcache(struct Object *ob, int index); // void object_delete_ptcache(struct Object *ob, int index);
struct KeyBlock *object_insert_shape_key(struct Scene *scene, struct Object *ob, char *name, int from_mix);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -55,7 +55,7 @@ struct uiMenuItem;
ED_spacetypes_init() in editors/area/spacetypes.c */ ED_spacetypes_init() in editors/area/spacetypes.c */
/* an editor in Blender is a combined ScrArea + SpaceType + SpaceData */ /* an editor in Blender is a combined ScrArea + SpaceType + SpaceData */
#define BKE_ST_MAXNAME 32 #define BKE_ST_MAXNAME 64
typedef struct SpaceType { typedef struct SpaceType {
struct SpaceType *next, *prev; struct SpaceType *next, *prev;
@@ -220,8 +220,6 @@ const struct ListBase *BKE_spacetypes_list(void);
void BKE_spacetype_register(struct SpaceType *st); void BKE_spacetype_register(struct SpaceType *st);
void BKE_spacetypes_free(void); /* only for quitting blender */ void BKE_spacetypes_free(void); /* only for quitting blender */
// MenuType *BKE_spacemenu_find(const char *idname, int spacetype);
/* spacedata */ /* spacedata */
void BKE_spacedata_freelist(ListBase *lb); void BKE_spacedata_freelist(ListBase *lb);
void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2); void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);

View File

@@ -195,7 +195,7 @@ void free_imbuf_seq(struct Scene *scene, struct ListBase * seqbasep, int check_m
void seq_update_sound(struct Sequence *seq); void seq_update_sound(struct Sequence *seq);
void seq_update_muting(struct Editing *ed); void seq_update_muting(struct Editing *ed);
void seqbase_sound_reload(Scene *scene, ListBase *seqbase);
void clear_scene_in_allseqs(struct Scene *sce); void clear_scene_in_allseqs(struct Scene *sce);
struct Sequence *get_seq_by_name(struct ListBase *seqbase, const char *name, int recursive); struct Sequence *get_seq_by_name(struct ListBase *seqbase, const char *name, int recursive);

View File

@@ -37,17 +37,19 @@ extern "C" {
/* generic blender movie support, could move to own module */ /* generic blender movie support, could move to own module */
struct RenderData; struct RenderData;
struct ReportList;
struct Scene; struct Scene;
void start_avi(struct Scene *scene, struct RenderData *rd, int rectx, int recty);
int start_avi(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports);
void end_avi(void); void end_avi(void);
void append_avi(struct RenderData *rd, int frame, int *pixels, int rectx, int recty); int append_avi(struct RenderData *rd, int frame, int *pixels, int rectx, int recty, struct ReportList *reports);
void makeavistring (struct RenderData *rd, char *string); void makeavistring (struct RenderData *rd, char *string);
typedef struct bMovieHandle { typedef struct bMovieHandle {
void (*start_movie)(struct Scene *scene, struct RenderData *rd, int rectx, int recty); int (*start_movie)(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports);
void (*append_movie)(struct RenderData *rd, int frame, int *pixels, int rectx, int recty); int (*append_movie)(struct RenderData *rd, int frame, int *pixels, int rectx, int recty, struct ReportList *reports);
void (*end_movie)(void); void (*end_movie)(void);
int (*get_next_frame)(struct RenderData *rd); /* optional */ int (*get_next_frame)(struct RenderData *rd, struct ReportList *reports); /* optional */
} bMovieHandle; } bMovieHandle;
bMovieHandle *BKE_get_movie_handle(int imtype); bMovieHandle *BKE_get_movie_handle(int imtype);

View File

@@ -57,11 +57,12 @@ extern "C" {
struct IDProperty; struct IDProperty;
struct RenderData; struct RenderData;
struct ReportList;
struct Scene; struct Scene;
extern void start_ffmpeg(struct Scene *scene, struct RenderData *rd, int rectx, int recty); extern int start_ffmpeg(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports);
extern void end_ffmpeg(void); extern void end_ffmpeg(void);
extern void append_ffmpeg(struct RenderData *rd, int frame, int *pixels, int rectx, int recty); extern int append_ffmpeg(struct RenderData *rd, int frame, int *pixels, int rectx, int recty, struct ReportList *reports);
extern void ffmpeg_set_preset(struct RenderData *rd, int preset); extern void ffmpeg_set_preset(struct RenderData *rd, int preset);
extern void ffmpeg_verify_image_type(struct RenderData *rd); extern void ffmpeg_verify_image_type(struct RenderData *rd);

View File

@@ -33,12 +33,13 @@ extern "C" {
#endif #endif
struct RenderData; struct RenderData;
struct ReportList;
struct Scene; struct Scene;
extern void start_frameserver(struct Scene *scene, struct RenderData *rd, int rectx, int recty); extern int start_frameserver(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports);
extern void end_frameserver(void); extern void end_frameserver(void);
extern void append_frameserver(struct RenderData *rd, int frame, int *pixels, int rectx, int recty); extern int append_frameserver(struct RenderData *rd, int frame, int *pixels, int rectx, int recty, struct ReportList *reports);
extern int frameserver_loop(struct RenderData *rd); extern int frameserver_loop(struct RenderData *rd, struct ReportList *reports);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -379,19 +379,10 @@ bActionGroup *action_groups_find_named (bAction *act, const char name[])
/* usually used within a loop, so we got a N^2 slowdown */ /* usually used within a loop, so we got a N^2 slowdown */
bPoseChannel *get_pose_channel(const bPose *pose, const char *name) bPoseChannel *get_pose_channel(const bPose *pose, const char *name)
{ {
bPoseChannel *chan;
if (ELEM(NULL, pose, name) || (name[0] == 0)) if (ELEM(NULL, pose, name) || (name[0] == 0))
return NULL; return NULL;
for (chan=pose->chanbase.first; chan; chan=chan->next) { return BLI_findstring(&pose->chanbase, name, offsetof(bPoseChannel, name));
if (chan->name[0] == name[0]) {
if (!strcmp (chan->name, name))
return chan;
}
}
return NULL;
} }
/* Use with care, not on Armature poses but for temporal ones */ /* Use with care, not on Armature poses but for temporal ones */

View File

@@ -72,7 +72,7 @@ static short id_has_animdata (ID *id)
switch (GS(id->name)) { switch (GS(id->name)) {
/* has AnimData */ /* has AnimData */
case ID_OB: case ID_OB:
case ID_MB: case ID_CU: case ID_AR: case ID_ME: case ID_MB: case ID_CU: case ID_AR:
case ID_KE: case ID_KE:
case ID_PA: case ID_PA:
case ID_MA: case ID_TE: case ID_NT: case ID_MA: case ID_TE: case ID_NT:
@@ -1774,7 +1774,7 @@ void BKE_animsys_evaluate_all_animation (Main *main, float ctime)
EVAL_ANIM_IDS(main->armature.first, ADT_RECALC_ANIM); EVAL_ANIM_IDS(main->armature.first, ADT_RECALC_ANIM);
/* meshes */ /* meshes */
// TODO... EVAL_ANIM_IDS(main->mesh.first, ADT_RECALC_ANIM);
/* particles */ /* particles */
EVAL_ANIM_IDS(main->particle.first, ADT_RECALC_ANIM); EVAL_ANIM_IDS(main->particle.first, ADT_RECALC_ANIM);

View File

@@ -40,6 +40,8 @@
#include "DNA_scene_types.h" #include "DNA_scene_types.h"
#include "DNA_windowmanager_types.h" #include "DNA_windowmanager_types.h"
#include "WM_types.h"
#include "RNA_access.h" #include "RNA_access.h"
#include "BLI_math.h" #include "BLI_math.h"
@@ -56,6 +58,8 @@
#include "BKE_texture.h" #include "BKE_texture.h"
#include "BKE_utildefines.h" #include "BKE_utildefines.h"
#include "IMB_imbuf.h" #include "IMB_imbuf.h"
#include "IMB_imbuf_types.h" #include "IMB_imbuf_types.h"

View File

@@ -1006,7 +1006,7 @@ int CustomData_get_clone_layer_index(const CustomData *data, int type)
return -1; return -1;
} }
int CustomData_get_mask_layer_index(const CustomData *data, int type) int CustomData_get_stencil_layer_index(const CustomData *data, int type)
{ {
int i; int i;
@@ -1050,7 +1050,7 @@ int CustomData_get_clone_layer(const CustomData *data, int type)
return -1; return -1;
} }
int CustomData_get_mask_layer(const CustomData *data, int type) int CustomData_get_stencil_layer(const CustomData *data, int type)
{ {
int i; int i;
@@ -1088,7 +1088,7 @@ void CustomData_set_layer_clone(CustomData *data, int type, int n)
data->layers[i].active_clone = n; data->layers[i].active_clone = n;
} }
void CustomData_set_layer_mask(CustomData *data, int type, int n) void CustomData_set_layer_stencil(CustomData *data, int type, int n)
{ {
int i; int i;
@@ -1125,7 +1125,7 @@ void CustomData_set_layer_clone_index(CustomData *data, int type, int n)
data->layers[i].active_clone = n-i; data->layers[i].active_clone = n-i;
} }
void CustomData_set_layer_mask_index(CustomData *data, int type, int n) void CustomData_set_layer_stencil_index(CustomData *data, int type, int n)
{ {
int i; int i;

Some files were not shown because too many files have changed in this diff Show More