* ensure all SConscripts are ready for win64-vc (where necessary).
* ensure we have proper _DEBUG flag for Python when we're doing a debug build.
* some cleaning up of linking etc.
* ensure /EHsc is there for game engine modules.
* Removed modules Expression and CValue, neither were ever available.
* Added GameLogic.EvalExpression(exp) from the Expression module, evaluates an expression like the expression controller (not sure if this is really that useful since python is far more advanced).
* resetting the original blend file path didint work (own fault == -> =)
* Py3.x PyModule_Create didnt allow importing since it didn't add to sys.modules,
Looks like they want us to use init-tab array, but this doesn't suit us since
it needs to be setup before python is initialized.
* Documented GameLogic.globalDict
svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r19820:HEAD
Notes:
* Game and sequencer RNA, and sequencer header are now out of date
a bit after changes in trunk.
* I didn't know how to port these bugfixes, most likely they are
not needed anymore.
* Fix "duplicate strip" always increase the user count for ipo.
* IPO pinning on sequencer strips was lost during Undo.
- Removed/Commented some unused vars
- CValue::GetPropertyText() could return a temp reference to a variable on the stack, option wasnt used anywhere so removed.
- KX_ConstraintWrapper::GetConstraintId allows args but ignored them
- KX_ConstraintWrapper::PySetParam didnt return NULL on an error (messing up pythons exceptions).
- BLI_natstrcmp didnt return 0 when the while loop exited
SCA_RandomActuator: The random generator was shared between replicas and not deleted. Added ref counting between replicas to allow deletion at the end.
KX_Camera: The scenegraph node was not deleted for temporary cameras (ImageMirror and shadow), causing 500 bytes leak per frame and per shadow light.
KX_GameActuator: Global dictionary buffer was not deleted after saving.
KX_MotionState: The motion state for compound child was not deleted
KX_ReplaceMeshActuator: The mesh was unnecessarily converted for each actuator and not deleted, causing large memleak.
After these fix, YoFrankie runs without memleak.
This commit extend the technique of dynamic linked list to the mesh
slots so as to eliminate dumb scan or map lookup. It provides massive
performance improvement in the culling and in the rasterizer when
the majority of objects are static.
Other improvements:
- Compute the opengl matrix only for objects that are visible.
- Simplify hash function for GEN_HasedPtr
- Scan light list instead of general object list to render shadows
- Remove redundant opengl calls to set specularity, shinyness and diffuse
between each mesh slots.
- Cache GPU material to avoid frequent call to GPU_material_from_blender
- Only set once the fixed elements of mesh slot
- Use more inline function
The following table shows the performance increase between 2.48, 1st round
and this round of improvement. The test was done with a scene containing
40000 objects, of which 1000 are in the view frustrum approximately. The
object are simple textured cube to make sure the GPU is not the bottleneck.
As some of the rasterizer processing time has moved under culling, I present
the sum of scenegraph(includes culling)+rasterizer time
Scenegraph+rasterizer(ms) 2.48 1st round 3rd round
All objects static, 323.0 86.0 7.2
all visible, 1000 in
the view frustrum
All objects static, 219.0 49.7 N/A(*)
all invisible.
All objects moving, 323.0 105.6 34.7
all visible, 1000 in
the view frustrum
Scene destruction 40min 40min 4s
(*) : this time is not representative because the frame rate was at 60fps.
In that case, the GPU holds down the GE by frame sync. By design, the
overhead of the rasterizer is 0 when the the objects are invisible.
This table shows a global speed up between 9x and 45x compared to 2.48a
for scenegraph, culling and rasterizer overhead. The speed up goes much
higher when objects are invisible.
An additional 2-4x speed up is possible in the scenegraph by upgrading
the Moto library to use Eigen2 BLAS library instead of C++ classes but
the scenegraph is already so fast that it is not a priority right now.
Next speed up in logic: many things to do there...
I added module clearing before there was checks for invalid python objects, so now its not needed for BGE Builtin types at least.
also made the builtin modules get re-used if they already exist and clear all user modules when the game engine finishes so with Module-Py-Controllers the referenced modules are at least up to date when pressing Pkey.
- More verbose error messages.
- BL_Shader wasnt setting error messages on some errors
- FilterNormal depth attribute was checking for float which is bad because scripts often expect ints assigned to float attributes.
- Added a check to PyVecTo for a tuple rather then always using a generic python sequence. On my system this is over 2x faster with an optmized build.
This changes how the BGE classes and Python work together, which hasnt changed since blender went opensource.
The main difference is PyObjectPlus - the base class for most game engine classes, no longer inherit from PyObject, and cannot be cast to a PyObject.
This has the advantage that the BGE does not have to keep 2 reference counts valid for C++ and Python.
Previously C++ classes would never be freed while python held a reference, however this reference could be problematic eg: a GameObject that isnt in a scene anymore should not be used by python, doing so could even crash blender in some cases.
Instead PyObjectPlus has a member "PyObject *m_proxy" which is lazily initialized when python needs it. m_proxy reference counts are managed by python, though it should never be freed while the C++ class exists since it holds a reference to avoid making and freeing it all the time.
When the C++ class is free'd it sets the m_proxy reference to NULL, If python accesses this variable it will raise a RuntimeError, (check the isValid attribute to see if its valid without raising an error).
- This replaces the m_zombie bool and IsZombie() tests added recently.
In python return values that used to be..
return value->AddRef();
Are now
return value->GetProxy();
or...
return value->NewProxy(true); // true means python owns this C++ value which will be deleted when the PyObject is freed
Other small changes...
- KX_Camera and KX_Light didnt have get/setitem access in their PyType definition.
- CList.from_id() error checking for a long was checking for -1 against an unsigned value (own fault)
- CValue::SpecialRelease was incrementing an int for no reason.
- renamed m_attrlist to m_attr_dict since its a PyDict type.
- removed custom getattro/setattro functions for KX_Scene and KX_GameObject, use py_base_getattro, py_base_setattro for all subclasses of PyObjectPlus.
- lowercase windows.h in VideoBase.cpp for cross compiling.
Added occlusion culling capability in the BGE.
More info: http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.49/Game_Engine#BGE_Scenegraph_improvement
MSVC, scons, cmake, Makefile updated.
Other minor performance improvements:
- The rasterizer was computing the openGL model matrix of the objects too many times
- DBVT view frustrum culling was not properly culling behind the near plane:
Large objects behind the camera were sent to the GPU
- Remove all references to mesh split/join feature as it is not yet functional
Notes:
* Sequence transform strip uses G.scene global, this is commented
out now, should be fixed.
* Etch-a-ton code was most difficult to merge. The files already in
2.5 got merged, but no new files were added. Calls to these files
are commented out with "XXX etch-a-ton". editarmature.c and
transform_snap.c were complex to merge. Martin, please check?
* Game engine compiles and links again here for scons/make/cmake
(player still fails to link).
The multi-thread cache service is activated only on multi-core processors.
It consists in loading, decoding and caching the video frames in a
separate thread. The cache size is 5 decoded frames and 30 raw frames.
Note that the opening of video file/stream/camera is not multi-thread:
you will still experience a delay at the VideoFFmpeg object creation.
Processing of the video frame (resize, loading to texture) is still done
in the main thread. Caching is automatically enabled for video file,
video streaming and video camera.
Video streaming now works correctly: the videos frames are loaded
at the correct rate. Network delays and frequency drifts are automatically
compensated.
Note: an http video source is always treated as a streaming source,
even though the http protocol allows seeking. For the user it means that
he cannot define start/stop range and cannot restart the video except
by reopening the source. Pause/play is however possible.
Video camera is now correctly handled on Linux: it will not slow down the BGE.
A video camera is treated as a streaming source.
- variables that shadow vers declared earlier
- Py_Fatal print an error to the stderr
- gcc was complaining about the order of initialized vars (for classes)
- const return values for ints and bools didnt do anything.
- braces for ambiguous if statements
* giving compileflags, cc_compileflags and cxx_compileflags to BlenderLib() now actually overrides any other setting (so there's no unclarity when ie. conflicting options are being specified in REL_CFLAGS et al). These are set after either release or debug flags, but before any *_WARN flags (so those stay maintained).
* add cxx_compileflags for GE parts on win32-vc to have better performance.
* NOTE: if platform maintainers (OSX and Linux) could check and do the same for their systems. Not vital, but probably very, very much welcomed by GE users.
The new class VideoTexture.ImageMirror() is available to perform
automatic mirror rendering.
Constructor:
VideoTexture.ImageMirror(scene,observer,mirror,material)
scene: reference to the scene that will be rendered.
Both observer and mirror must be part of that scene.
observer: reference to a game object used as view point for
mirror rendering: the scene will be rendered through
the mirror as if the active camera was at the observer
location. Usually the observer is the active camera
but you can use any game obejct.
mirror: reference to the mesh object holding the mirror.
material: material ID of the mirror texture as returned by
VideoTexture.materialID(). The mirror is formed by
the polygons mapped to that material.
There are no specific methods or attributes. ImageMirror inherits
all methods and attributes from ImageRender. You must refresh the
parent VideoTexture.Texture object regularly to update the mirror
rendering.
Guidelines on how to create a working mirror:
- Use a texture that is specific to the mirror so that the mirror
rendering only appears on the mirror.
- The mirror must be planar; the algorithm works well only for planar
or quasi planar mirror. For spherical mirror, you will get better
results with ImageRender and a camera at the center of the mirror.
ImageMirror automatically computes the mirror orientation and
position. The mirror doesn't need to be rectangular, it can be
circular or take any form provided it is planar.
- The mirror up direction must be along the Z axis in local mesh
coordinates. If the mirror is not vertical, ImageMirror will
compute the up direction as being the projection of the Z axis
on the mirror plane.
- UV mapping must be set right to get correct mirror rendering:
- make a planar projection of the mirror polygons (Unwrap or projection from view)
- eventually rotate the projection so that UV up direction corresponds to the mesh Z axis
- scale the projection so that the extreme points touch the border of the texture
- flip the UV projection horizontally (scale -1 on X axis). This is needed
because the mirror texture is rendered from the back of the mirror and
thus is reversed from the view point of the observer. Horizontal flip
in the UV map restores the correct orientation.
Besides these simple rules, the mirror rendering is completely automatic.
In particular, you don't need to allocate a camera for the rendering,
ImageMirror creates dynamically a camera for that. The reflection is correct
even on large angles. The mirror can be a dynamic and moving object, the
algorithm always computes the correct camera position based on observer
relative position. You don't have to worry about mirror position in the scene:
the algorithm automatically computes the camera frustum so that any object
behind the mirror is not rendered.
Warnings:
- observer and mirror are references to game objects. ImageMirror keeps
a pointer to them but does not increment the reference count. You must ensure
that these game objects are not deleted as long as you refresh() the ImageMirror
object. You must release the ImageMirror object before you delete the game
objects. To release the ImageMirror object (normally stored in GameLogic),
just assign it to None.
- Mirror rendering is automatically skipped when the observer is behind the mirror
but it is not disabled when the mirror is out of sight of the observer.
You should only refresh the mirror when you know that the observer is likely to see it.
For example, no need to refresh a car inner mirror when the player is not in the car.
Example:
contr = GameLogic.getCurrentController()
# object holding the mirror
mirror = contr.getOwner()
scene = GameLogic.getCurrentScene()
# observer will be the active camere
camera = scene.getObjectList()['OBCamera']
matID = VideoTexture.materialID(mirror, 'IMmirror.png')
GameLogic.mirror = VideoTexture.Texture(mirror, matID)
GameLogic.mirror.source = VideoTexture.ImageMirror(scene,camera,mirror,matID)
# to render the mirror, just call GameLogic.mirror.refresh(True) on each frame.
You can download a demo game (with a video file) here:
http://home.scarlet.be/~tsi46445/blender/VideoTextureDemo.zip
For those who have already downloaded the demo, you can just update the blend file:
http://home.scarlet.be/~tsi46445/blender/MirrorTextureDemo.blend
The new class VideoTexture.ImageRender() is available to perform
render to texture in the GE.
Constructor:
VideoTexture.ImageRender(scene,cam)
cam : camera object that will be used for the render.
It must be an inactive camera.
scene: reference to the scene that will be rendered.
The camera must be part of that scene.
Returns an object that can be used as a source of a VideoTexture.Texture object
Methods: none
Attributes:
background:
4-tuple representing the background color of the rendering
as RGBA color components, each component being an integer
between 0 and 255.
Default value = [0,0,255,255] (=saturated blue)
Note: athough the alpha component can be specified, it is not
supported at the moment, the alpha channel of the rendered
texture will always be 255. You can however introduce an
alpha channel by appending a FilterBlueScreen() filter, it
will set the alpha to 0 (transparent) on all pixels that were
not rendered.
capsize:
2-tuple representing the size of the render area as [x,y] number of pixels.
Default value = largest rectangle with power of 2 dimensions that fits in the canvas
You may want to reduce the render area to increase performance. For example,
a render area of [256,128] is probably sufficient to implement a car inner mirror.
For best performance, use power of 2 dimensions and don't set any filter: this
allows direct transfer between the GPU frame buffer and texture memory
without going through the host.
alpha:
Boolean indicating if the render alpha channel should be copied to the texture.
Default value: False
Experimental, do not use.
whole:
Boolean indicating if the entire canvas should be used for the rendering.
Default value: False
Note: There is no reason to set this attribute to True: the rendering will
in any case be scaled down to the largest rectangle with power of 2
dimensions before transfering to the texture.
Attributes inherited from the ImageBase class:
image : image binary data, read-only
size : [x,y] size of the texture, read-only
scale : set to True for fast scale down in case the render area dimensions are not power of 2
flip : set to True for vertical flip.
filter: set a post-processing filter on the render.
Notes:
* Aspect Ratio
For consistent results in Blender and Blenderplayer, the same aspect ratio used
by Blender to draw the camera viewport (Scene(F10)->Format tab->Size X/Size Y)
is also used during the rendering. You can control the portion of the scene that
will be rendered by "looking through the camera": the zone inside the outer dotted
rectangle will be rendered to the texture.
In order to reproduce the scene without X/Y distortion, you must apply the texture
on an object or portion of object that has the same aspect ratio.
* Order of rendering
The rendereing is performed when you call the refresh() method of the parent
Texture object. This happens outside the normal frame rendering and will have no
effect on it.
However, if you want to use ImageViewport and ImageRender at the same time, be
sure to refresh the viewport texture before the render texture because the latter
will destroy the frame buffer that is used by the former to update the texture.
* Scene status
The meshes are not updated during the render to texture: the rendered texture
is one frame late to the rendered frame with regards to mesh deformation.
* Example:
cont = GameLogic.getCurrentController()
# object that receives the texture
obj = contr.getOwner()
scene = GameLogic.getCurrentScene()
# camera used for the render
tvcam = scene.getObjectList()['OBtvcam']
# assume obj has some faces UV assigned to tv.png
matID = VideoTexture.materialID(obj, 'IMtv.png')
GameLogic.tv = VideoTexture.Texture(obj, matID)
GameLogic.tv.source = VideoTexture.ImageRender(scene,tvcam)
GameLogic.tv.source.capsize = [256,256]
# to render the texture, just call GameLogic.tv.refresh(True) on each frame.
You can download a demo game (with a video file) here:
http://home.scarlet.be/~tsi46445/blender/VideoTextureDemo.zip
For those who have already downloaded the demo, you can just update the blend file:
http://home.scarlet.be/~tsi46445/blender/VideoTextureDemo.blend
svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r12987:17416
Issues:
* GHOST/X11 had conflicting changes. Some code was added in 2.5, which was
later added in trunk also, but reverted partially, specifically revision
16683. I have left out this reversion in the 2.5 branch since I think it is
needed there.
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16683
* Scons had various conflicting changes, I decided to go with trunk version
for everything except priorities and some library renaming.
* In creator.c, there were various fixes and fixes for fixes related to the -w
-W and -p options. In 2.5 -w and -W is not coded yet, and -p is done
differently. Since this is changed so much, and I don't think those fixes
would be needed in 2.5, I've left them out.
* Also in creator.c: there was code for a python bugfix where the screen was not
initialized when running with -P. The code that initializes the screen there
I had to disable, that can't work in 2.5 anymore but left it commented as a
reminder.
Further I had to disable some new function calls. using src/ and python/, as
was done already in this branch, disabled function calls:
* bpath.c: error reporting
* BME_conversions.c: editmesh conversion functions.
* SHD_dynamic: disabled almost completely, there is no python/.
* KX_PythonInit.cpp and Ketsji/ build files: Mathutils is not there, disabled.
* text.c: clipboard copy call.
* object.c: OB_SUPPORT_MATERIAL.
* DerivedMesh.c and subsurf_ccg, stipple_quarttone.
Still to be done:
* Go over files and functions that were moved to a different location but could
still use changes that were done in trunk.
You can specify a image name (starting with 'IM') instead of a material
name in VideoTexture.materialID() and return the material ID matching
this texture.
The advantage of this method is that is works with blender material
and UV texture. In case of UV texture, it grabs the internal material
corresponding to the faces that are assigned to this texture. In case
of blender material, it grabs the material that has an image texture
matching the name as first texture channel.
In both cases, the texture id used in VideoTexture.Texture() should be 0.
Ex:
matID = VideoTexture.materialID(obj,'IMvideo.png')
GameLogic.video = VideoTexture.Texture(obj, matID, 0)
The FFmpeg library allows to load image files. Although it is possible
to load images using the VideoFFmpeg class, it is not very efficient.
The new class VideoTexture.ImageFFmpeg is dedicated to image management.
Constructor:
-----------
VideoTexture.ImageFFmpeg('image_file_name')
Opens the file but does not load the texture yet.
The file name can also be a network address. It can also be a video
file name; in that case only the first image is loaded.
Methods:
-------
refresh(True)
Loads the image to texture.
You just need to call it once, the file is automatically closed after
that and calling refresh() again will have no effect.
reload('new_file_name')
Reloads the image (if new_file_name is omitted) or loads a new image.
The file is opened but the texture is not updated yet, you need
to call refresh() once to load the texture.
Attributes:
----------
status
returns the image status:
2 : file opened, texture not loaded
3 : file closed, texture loaded
image
returns the image data as a string of RGBA pixel
size
returns the image size [x,y]
scale
get/set the scale flag.
If the scale flag is False, the image is rescale to texture format
using gluScaleImage() function, slow but good quality.
If the scale flag is True, the image is rescaled using a fast but
less accurate algorithm.
flip
get/set Y-flip flag.
Set to True by default as FFmpeg always provides the image upside down
filter
get/set filter(s) on the image.
Example: