Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Eagar <joeedh@gmail.com>2009-10-24 09:43:27 +0400
committerJoseph Eagar <joeedh@gmail.com>2009-10-24 09:43:27 +0400
commit672c8926d7801fcc4b45e9dff75022e1ff9d240b (patch)
tree33dfc4620f52af667b4c251d0a940de86118dcc7
parent8f788c64db587e74079d812dbcea40c2bd4b91ff (diff)
parent6ffb79107c9509f01019c8bf9af2caf0348ca330 (diff)
files missing from recent merge
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerCocoa.h106
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerCocoa.mm168
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.h273
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm1396
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.h295
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm1028
-rw-r--r--source/blender/editors/mesh/bmesh_tools.c3
-rw-r--r--source/blender/gpu/gpu_buffers.h157
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c1262
-rw-r--r--source/blender/makesrna/intern/rna_action_api.c80
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c101
-rw-r--r--source/blender/makesrna/intern/rna_material_api.c126
-rw-r--r--source/blender/makesrna/intern/rna_pose_api.c56
-rw-r--r--source/gameengine/Converter/BL_ArmatureActuator.cpp267
-rw-r--r--source/gameengine/Converter/BL_ArmatureActuator.h93
-rw-r--r--source/gameengine/Converter/BL_ArmatureChannel.cpp469
-rw-r--r--source/gameengine/Converter/BL_ArmatureChannel.h95
-rw-r--r--source/gameengine/Converter/BL_ArmatureConstraint.cpp454
-rw-r--r--source/gameengine/Converter/BL_ArmatureConstraint.h118
-rw-r--r--source/gameengine/GameLogic/SCA_BasicEventManager.cpp61
-rw-r--r--source/gameengine/GameLogic/SCA_BasicEventManager.h57
-rw-r--r--source/gameengine/Ketsji/KX_ArmatureSensor.cpp208
-rw-r--r--source/gameengine/Ketsji/KX_ArmatureSensor.h89
23 files changed, 6961 insertions, 1 deletions
diff --git a/intern/ghost/intern/GHOST_DisplayManagerCocoa.h b/intern/ghost/intern/GHOST_DisplayManagerCocoa.h
new file mode 100644
index 00000000000..0ce5e08b4f6
--- /dev/null
+++ b/intern/ghost/intern/GHOST_DisplayManagerCocoa.h
@@ -0,0 +1,106 @@
+/**
+ * $Id: GHOST_DisplayManagerCocoa.h 23603 2009-10-02 07:20:33Z damien78 $
+ * ***** 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 *****
+ */
+/**
+ * @file GHOST_DisplayManagerCocoa.h
+ * Declaration of GHOST_DisplayManagerCocoa class.
+ */
+
+#ifndef _GHOST_DISPLAY_MANAGER_COCOA_H_
+#define _GHOST_DISPLAY_MANAGER_COCOA_H_
+
+#ifndef __APPLE__
+#error Apple only!
+#endif // __APPLE__
+
+#include "GHOST_DisplayManager.h"
+
+/**
+ * Manages system displays (Mac OSX/Cocoa implementation).
+ * @see GHOST_DisplayManager
+ * @author Maarten Gribnau
+ * @date September 21, 2001
+ */
+class GHOST_DisplayManagerCocoa : public GHOST_DisplayManager
+{
+public:
+ /**
+ * Constructor.
+ */
+ GHOST_DisplayManagerCocoa(void);
+
+ /**
+ * Returns the number of display devices on this system.
+ * @param numDisplays The number of displays on this system.
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess getNumDisplays(GHOST_TUns8& numDisplays) const;
+
+ /**
+ * Returns the number of display settings for this display device.
+ * @param display The index of the display to query with 0 <= display < getNumDisplays().
+ * @param setting The number of settings of the display device with this index.
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const;
+
+ /**
+ * Returns the current setting for this display device.
+ * @param display The index of the display to query with 0 <= display < getNumDisplays().
+ * @param index The setting index to be returned.
+ * @param setting The setting of the display device with this index.
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const;
+
+ /**
+ * Returns the current setting for this display device.
+ * @param display The index of the display to query with 0 <= display < getNumDisplays().
+ * @param setting The current setting of the display device with this index.
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const;
+
+ /**
+ * Changes the current setting for this display device.
+ * @param display The index of the display to query with 0 <= display < getNumDisplays().
+ * @param setting The current setting of the display device with this index.
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting);
+
+protected:
+ //Do not cache values as OS X supports screen hot plug
+ /** Cached number of displays. */
+ //CGDisplayCount m_numDisplays;
+ /** Cached display id's for each display. */
+ //CGDirectDisplayID* m_displayIDs;
+};
+
+
+#endif // _GHOST_DISPLAY_MANAGER_COCOA_H_
+
diff --git a/intern/ghost/intern/GHOST_DisplayManagerCocoa.mm b/intern/ghost/intern/GHOST_DisplayManagerCocoa.mm
new file mode 100644
index 00000000000..5be49851bcb
--- /dev/null
+++ b/intern/ghost/intern/GHOST_DisplayManagerCocoa.mm
@@ -0,0 +1,168 @@
+/**
+ * $Id: GHOST_DisplayManagerCocoa.mm 23603 2009-10-02 07:20:33Z damien78 $
+ * ***** 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): Maarten Gribnau 09/2001
+ Damien Plisson 10/2009
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <Cocoa/Cocoa.h>
+
+#include "GHOST_DisplayManagerCocoa.h"
+#include "GHOST_Debug.h"
+
+// We do not support multiple monitors at the moment
+
+
+GHOST_DisplayManagerCocoa::GHOST_DisplayManagerCocoa(void)
+{
+}
+
+
+GHOST_TSuccess GHOST_DisplayManagerCocoa::getNumDisplays(GHOST_TUns8& numDisplays) const
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ numDisplays = (GHOST_TUns8) [[NSScreen screens] count];
+
+ [pool drain];
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_DisplayManagerCocoa::getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const
+{
+ GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCocoa::getNumDisplaySettings(): only main display is supported");
+
+ numSettings = (GHOST_TInt32)3; //Width, Height, BitsPerPixel
+
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_DisplayManagerCocoa::getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const
+{
+ //Note that only current display setting is available
+ NSScreen *askedDisplay;
+
+ GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCocoa::getDisplaySetting(): only main display is supported");
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ if (display == kMainDisplay) //Screen #0 may not be the main one
+ askedDisplay = [NSScreen mainScreen];
+ else
+ askedDisplay = [[NSScreen screens] objectAtIndex:display];
+
+ if(askedDisplay == nil) {
+ [pool drain];
+ return GHOST_kFailure;
+ }
+
+ NSRect frame = [askedDisplay visibleFrame];
+ setting.xPixels = frame.size.width;
+ setting.yPixels = frame.size.height;
+
+ setting.bpp = NSBitsPerPixelFromDepth([askedDisplay depth]);
+
+ setting.frequency = 0; //No more CRT display...
+
+#ifdef GHOST_DEBUG
+ printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", setting.xPixels, setting.yPixels, setting.bpp, setting.frequency);
+#endif // GHOST_DEBUG
+
+ [pool drain];
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_DisplayManagerCocoa::getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const
+{
+ NSScreen *askedDisplay;
+
+ GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCocoa::getCurrentDisplaySetting(): only main display is supported");
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ if (display == kMainDisplay) //Screen #0 may not be the main one
+ askedDisplay = [NSScreen mainScreen];
+ else
+ askedDisplay = [[NSScreen screens] objectAtIndex:display];
+
+ if(askedDisplay == nil) {
+ [pool drain];
+ return GHOST_kFailure;
+ }
+
+ NSRect frame = [askedDisplay visibleFrame];
+ setting.xPixels = frame.size.width;
+ setting.yPixels = frame.size.height;
+
+ setting.bpp = NSBitsPerPixelFromDepth([askedDisplay depth]);
+
+ setting.frequency = 0; //No more CRT display...
+
+#ifdef GHOST_DEBUG
+ printf("current display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", setting.xPixels, setting.yPixels, setting.bpp, setting.frequency);
+#endif // GHOST_DEBUG
+
+ [pool drain];
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting)
+{
+ GHOST_ASSERT((display==kMainDisplay), "GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(): only main display is supported");
+
+#ifdef GHOST_DEBUG
+ printf("GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(): requested settings:\n");
+ printf(" setting.xPixels=%d\n", setting.xPixels);
+ printf(" setting.yPixels=%d\n", setting.yPixels);
+ printf(" setting.bpp=%d\n", setting.bpp);
+ printf(" setting.frequency=%d\n", setting.frequency);
+#endif // GHOST_DEBUG
+
+ //Display configuration is no more available in 10.6
+
+/* CFDictionaryRef displayModeValues = ::CGDisplayBestModeForParametersAndRefreshRate(
+ m_displayIDs[display],
+ (size_t)setting.bpp,
+ (size_t)setting.xPixels,
+ (size_t)setting.yPixels,
+ (CGRefreshRate)setting.frequency,
+ NULL);*/
+
+#ifdef GHOST_DEBUG
+ printf("GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(): switching to:\n");
+ printf(" setting.xPixels=%d\n", getValue(displayModeValues, kCGDisplayWidth));
+ printf(" setting.yPixels=%d\n", getValue(displayModeValues, kCGDisplayHeight));
+ printf(" setting.bpp=%d\n", getValue(displayModeValues, kCGDisplayBitsPerPixel));
+ printf(" setting.frequency=%d\n", getValue(displayModeValues, kCGDisplayRefreshRate));
+#endif // GHOST_DEBUG
+
+ //CGDisplayErr err = ::CGDisplaySwitchToMode(m_displayIDs[display], displayModeValues);
+
+ return /*err == CGDisplayNoErr ? GHOST_kSuccess :*/ GHOST_kFailure;
+}
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h
new file mode 100644
index 00000000000..002089e4185
--- /dev/null
+++ b/intern/ghost/intern/GHOST_SystemCocoa.h
@@ -0,0 +1,273 @@
+/**
+ * $Id: GHOST_SystemCocoa.h 23737 2009-10-09 12:48:28Z damien78 $
+ * ***** 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): Maarten Gribnau 05/2001
+ * Damien Plisson 09/2009
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+/**
+ * @file GHOST_SystemCocoa.h
+ * Declaration of GHOST_SystemCocoa class.
+ */
+
+#ifndef _GHOST_SYSTEM_COCOA_H_
+#define _GHOST_SYSTEM_COCOA_H_
+
+#ifndef __APPLE__
+#error Apple OSX only!
+#endif // __APPLE__
+
+//#define __CARBONSOUND__
+
+
+#include "GHOST_System.h"
+
+class GHOST_EventCursor;
+class GHOST_EventKey;
+class GHOST_EventWindow;
+class GHOST_WindowCocoa;
+
+
+class GHOST_SystemCocoa : public GHOST_System {
+public:
+ /**
+ * Constructor.
+ */
+ GHOST_SystemCocoa();
+
+ /**
+ * Destructor.
+ */
+ ~GHOST_SystemCocoa();
+
+ /***************************************************************************************
+ ** Time(r) functionality
+ ***************************************************************************************/
+
+ /**
+ * Returns the system time.
+ * Returns the number of milliseconds since the start of the system process.
+ * Based on ANSI clock() routine.
+ * @return The number of milliseconds.
+ */
+ virtual GHOST_TUns64 getMilliSeconds() const;
+
+ /***************************************************************************************
+ ** Display/window management functionality
+ ***************************************************************************************/
+
+ /**
+ * Returns the number of displays on this system.
+ * @return The number of displays.
+ */
+ virtual GHOST_TUns8 getNumDisplays() const;
+
+ /**
+ * Returns the dimensions of the main display on this system.
+ * @return The dimension of the main display.
+ */
+ virtual void getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const;
+
+ /**
+ * Create a new window.
+ * The new window is added to the list of windows managed.
+ * Never explicitly delete the window, use disposeWindow() instead.
+ * @param title The name of the window (displayed in the title bar of the window if the OS supports it).
+ * @param left The coordinate of the left edge of the window.
+ * @param top The coordinate of the top edge of the window.
+ * @param width The width the window.
+ * @param height The height the window.
+ * @param state The state of the window when opened.
+ * @param type The type of drawing context installed in this window.
+ * @param parentWindow Parent (embedder) window
+ * @return The new window (or 0 if creation failed).
+ */
+ virtual GHOST_IWindow* createWindow(
+ const STR_String& title,
+ GHOST_TInt32 left,
+ GHOST_TInt32 top,
+ GHOST_TUns32 width,
+ GHOST_TUns32 height,
+ GHOST_TWindowState state,
+ GHOST_TDrawingContextType type,
+ const bool stereoVisual,
+ const GHOST_TEmbedderWindowID parentWindow = 0
+ );
+
+ virtual GHOST_TSuccess beginFullScreen(
+ const GHOST_DisplaySetting& setting,
+ GHOST_IWindow** window,
+ const bool stereoVisual
+ );
+
+ virtual GHOST_TSuccess endFullScreen( void );
+
+ /***************************************************************************************
+ ** Event management functionality
+ ***************************************************************************************/
+
+ /**
+ * Gets events from the system and stores them in the queue.
+ * @param waitForEvent Flag to wait for an event (or return immediately).
+ * @return Indication of the presence of events.
+ */
+ virtual bool processEvents(bool waitForEvent);
+
+ /**
+ * Handle User request to quit, from Menu bar Quit, and Cmd+Q
+ * Display alert panel if changes performed since last save
+ */
+ GHOST_TUns8 handleQuitRequest();
+
+ /***************************************************************************************
+ ** Cursor management functionality
+ ***************************************************************************************/
+
+ /**
+ * Returns the current location of the cursor (location in screen coordinates)
+ * @param x The x-coordinate of the cursor.
+ * @param y The y-coordinate of the cursor.
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const;
+
+ /**
+ * Updates the location of the cursor (location in screen coordinates).
+ * @param x The x-coordinate of the cursor.
+ * @param y The y-coordinate of the cursor.
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const;
+
+ /***************************************************************************************
+ ** Access to mouse button and keyboard states.
+ ***************************************************************************************/
+
+ /**
+ * Returns the state of all modifier keys.
+ * @param keys The state of all modifier keys (true == pressed).
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys& keys) const;
+
+ /**
+ * Returns the state of the mouse buttons (ouside the message queue).
+ * @param buttons The state of the buttons.
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess getButtons(GHOST_Buttons& buttons) const;
+
+ /**
+ * Returns Clipboard data
+ * @param selection Indicate which buffer to return
+ * @return Returns the selected buffer
+ */
+ virtual GHOST_TUns8* getClipboard(bool selection) const;
+
+ /**
+ * Puts buffer to system clipboard
+ * @param buffer The buffer to be copied
+ * @param selection Indicates which buffer to copy too, only used on X11
+ */
+ virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const;
+
+ /**
+ * Handles a window event. Called by GHOST_WindowCocoa window delegate
+ * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++)
+ * @return Indication whether the event was handled.
+ */
+ GHOST_TSuccess handleWindowEvent(GHOST_TEventType eventType, GHOST_WindowCocoa* window);
+
+protected:
+ /**
+ * Initializes the system.
+ * For now, it justs registers the window class (WNDCLASS).
+ * @return A success value.
+ */
+ virtual GHOST_TSuccess init();
+
+ /**
+ * Handles a tablet event.
+ * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++)
+ * @param eventType The type of the event. It needs to be passed separately as it can be either directly in the event type, or as a subtype if combined with a mouse button event
+ * @return Indication whether the event was handled.
+ */
+ GHOST_TSuccess handleTabletEvent(void *eventPtr, short eventType);
+
+ /**
+ * Handles a mouse event.
+ * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++)
+ * @return Indication whether the event was handled.
+ */
+ GHOST_TSuccess handleMouseEvent(void *eventPtr);
+
+ /**
+ * Handles a key event.
+ * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++)
+ * @return Indication whether the event was handled.
+ */
+ GHOST_TSuccess handleKeyEvent(void *eventPtr);
+
+ /**
+ * Handles all basic Mac application stuff for a mouse down event.
+ * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++)
+ * @return Indication whether the event was handled.
+ */
+ // bool handleMouseDown(void *eventPtr);
+
+ /**
+ * Handles a Mac menu command.
+ * @param menuResult A Mac menu/item identifier.
+ * @return Indication whether the event was handled.
+ */
+ // bool handleMenuCommand(GHOST_TInt32 menuResult);
+
+ /* callback for blender generated events */
+// static OSStatus blendEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData);
+
+
+ /**
+ * Callback for Mac Timer tasks that expire.
+ * @param tmTask Pointer to the timer task that expired.
+ */
+ //static void s_timerCallback(TMTaskPtr tmTask);
+
+ /** Event handler reference. */
+ //EventHandlerRef m_handler;
+
+ /** Start time at initialization. */
+ GHOST_TUns64 m_start_time;
+
+ /** Mouse buttons state */
+ GHOST_TUns32 m_pressedMouseButtons;
+
+ /** State of the modifiers. */
+ GHOST_TUns32 m_modifierMask;
+
+ /** Ignores window size messages (when window is dragged). */
+ bool m_ignoreWindowSizedMessages;
+};
+
+#endif // _GHOST_SYSTEM_COCOA_H_
+
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
new file mode 100644
index 00000000000..b924adeebde
--- /dev/null
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -0,0 +1,1396 @@
+/**
+ * $Id: GHOST_SystemCocoa.mm 23854 2009-10-15 08:27:31Z damien78 $
+ * ***** 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): Maarten Gribnau 05/2001
+ * Damien Plisson 09/2009
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#import <Cocoa/Cocoa.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include "GHOST_SystemCocoa.h"
+
+#include "GHOST_DisplayManagerCocoa.h"
+#include "GHOST_EventKey.h"
+#include "GHOST_EventButton.h"
+#include "GHOST_EventCursor.h"
+#include "GHOST_EventWheel.h"
+#include "GHOST_EventNDOF.h"
+
+#include "GHOST_TimerManager.h"
+#include "GHOST_TimerTask.h"
+#include "GHOST_WindowManager.h"
+#include "GHOST_WindowCocoa.h"
+#include "GHOST_NDOFManager.h"
+#include "AssertMacros.h"
+
+#pragma mark KeyMap, mouse converters
+
+
+/* Keycodes from Carbon include file */
+/*
+ * Summary:
+ * Virtual keycodes
+ *
+ * Discussion:
+ * These constants are the virtual keycodes defined originally in
+ * Inside Mac Volume V, pg. V-191. They identify physical keys on a
+ * keyboard. Those constants with "ANSI" in the name are labeled
+ * according to the key position on an ANSI-standard US keyboard.
+ * For example, kVK_ANSI_A indicates the virtual keycode for the key
+ * with the letter 'A' in the US keyboard layout. Other keyboard
+ * layouts may have the 'A' key label on a different physical key;
+ * in this case, pressing 'A' will generate a different virtual
+ * keycode.
+ */
+enum {
+ kVK_ANSI_A = 0x00,
+ kVK_ANSI_S = 0x01,
+ kVK_ANSI_D = 0x02,
+ kVK_ANSI_F = 0x03,
+ kVK_ANSI_H = 0x04,
+ kVK_ANSI_G = 0x05,
+ kVK_ANSI_Z = 0x06,
+ kVK_ANSI_X = 0x07,
+ kVK_ANSI_C = 0x08,
+ kVK_ANSI_V = 0x09,
+ kVK_ANSI_B = 0x0B,
+ kVK_ANSI_Q = 0x0C,
+ kVK_ANSI_W = 0x0D,
+ kVK_ANSI_E = 0x0E,
+ kVK_ANSI_R = 0x0F,
+ kVK_ANSI_Y = 0x10,
+ kVK_ANSI_T = 0x11,
+ kVK_ANSI_1 = 0x12,
+ kVK_ANSI_2 = 0x13,
+ kVK_ANSI_3 = 0x14,
+ kVK_ANSI_4 = 0x15,
+ kVK_ANSI_6 = 0x16,
+ kVK_ANSI_5 = 0x17,
+ kVK_ANSI_Equal = 0x18,
+ kVK_ANSI_9 = 0x19,
+ kVK_ANSI_7 = 0x1A,
+ kVK_ANSI_Minus = 0x1B,
+ kVK_ANSI_8 = 0x1C,
+ kVK_ANSI_0 = 0x1D,
+ kVK_ANSI_RightBracket = 0x1E,
+ kVK_ANSI_O = 0x1F,
+ kVK_ANSI_U = 0x20,
+ kVK_ANSI_LeftBracket = 0x21,
+ kVK_ANSI_I = 0x22,
+ kVK_ANSI_P = 0x23,
+ kVK_ANSI_L = 0x25,
+ kVK_ANSI_J = 0x26,
+ kVK_ANSI_Quote = 0x27,
+ kVK_ANSI_K = 0x28,
+ kVK_ANSI_Semicolon = 0x29,
+ kVK_ANSI_Backslash = 0x2A,
+ kVK_ANSI_Comma = 0x2B,
+ kVK_ANSI_Slash = 0x2C,
+ kVK_ANSI_N = 0x2D,
+ kVK_ANSI_M = 0x2E,
+ kVK_ANSI_Period = 0x2F,
+ kVK_ANSI_Grave = 0x32,
+ kVK_ANSI_KeypadDecimal = 0x41,
+ kVK_ANSI_KeypadMultiply = 0x43,
+ kVK_ANSI_KeypadPlus = 0x45,
+ kVK_ANSI_KeypadClear = 0x47,
+ kVK_ANSI_KeypadDivide = 0x4B,
+ kVK_ANSI_KeypadEnter = 0x4C,
+ kVK_ANSI_KeypadMinus = 0x4E,
+ kVK_ANSI_KeypadEquals = 0x51,
+ kVK_ANSI_Keypad0 = 0x52,
+ kVK_ANSI_Keypad1 = 0x53,
+ kVK_ANSI_Keypad2 = 0x54,
+ kVK_ANSI_Keypad3 = 0x55,
+ kVK_ANSI_Keypad4 = 0x56,
+ kVK_ANSI_Keypad5 = 0x57,
+ kVK_ANSI_Keypad6 = 0x58,
+ kVK_ANSI_Keypad7 = 0x59,
+ kVK_ANSI_Keypad8 = 0x5B,
+ kVK_ANSI_Keypad9 = 0x5C
+};
+
+/* keycodes for keys that are independent of keyboard layout*/
+enum {
+ kVK_Return = 0x24,
+ kVK_Tab = 0x30,
+ kVK_Space = 0x31,
+ kVK_Delete = 0x33,
+ kVK_Escape = 0x35,
+ kVK_Command = 0x37,
+ kVK_Shift = 0x38,
+ kVK_CapsLock = 0x39,
+ kVK_Option = 0x3A,
+ kVK_Control = 0x3B,
+ kVK_RightShift = 0x3C,
+ kVK_RightOption = 0x3D,
+ kVK_RightControl = 0x3E,
+ kVK_Function = 0x3F,
+ kVK_F17 = 0x40,
+ kVK_VolumeUp = 0x48,
+ kVK_VolumeDown = 0x49,
+ kVK_Mute = 0x4A,
+ kVK_F18 = 0x4F,
+ kVK_F19 = 0x50,
+ kVK_F20 = 0x5A,
+ kVK_F5 = 0x60,
+ kVK_F6 = 0x61,
+ kVK_F7 = 0x62,
+ kVK_F3 = 0x63,
+ kVK_F8 = 0x64,
+ kVK_F9 = 0x65,
+ kVK_F11 = 0x67,
+ kVK_F13 = 0x69,
+ kVK_F16 = 0x6A,
+ kVK_F14 = 0x6B,
+ kVK_F10 = 0x6D,
+ kVK_F12 = 0x6F,
+ kVK_F15 = 0x71,
+ kVK_Help = 0x72,
+ kVK_Home = 0x73,
+ kVK_PageUp = 0x74,
+ kVK_ForwardDelete = 0x75,
+ kVK_F4 = 0x76,
+ kVK_End = 0x77,
+ kVK_F2 = 0x78,
+ kVK_PageDown = 0x79,
+ kVK_F1 = 0x7A,
+ kVK_LeftArrow = 0x7B,
+ kVK_RightArrow = 0x7C,
+ kVK_DownArrow = 0x7D,
+ kVK_UpArrow = 0x7E
+};
+
+/* ISO keyboards only*/
+enum {
+ kVK_ISO_Section = 0x0A
+};
+
+/* JIS keyboards only*/
+enum {
+ kVK_JIS_Yen = 0x5D,
+ kVK_JIS_Underscore = 0x5E,
+ kVK_JIS_KeypadComma = 0x5F,
+ kVK_JIS_Eisu = 0x66,
+ kVK_JIS_Kana = 0x68
+};
+
+
+static GHOST_TButtonMask convertButton(int button)
+{
+ switch (button) {
+ case 0:
+ return GHOST_kButtonMaskLeft;
+ case 1:
+ return GHOST_kButtonMaskRight;
+ case 2:
+ return GHOST_kButtonMaskMiddle;
+ case 3:
+ return GHOST_kButtonMaskButton4;
+ case 4:
+ return GHOST_kButtonMaskButton5;
+ default:
+ return GHOST_kButtonMaskLeft;
+ }
+}
+
+/**
+ * Converts Mac rawkey codes (same for Cocoa & Carbon)
+ * into GHOST key codes
+ * @param rawCode The raw physical key code
+ * @param recvChar the character ignoring modifiers (except for shift)
+ * @return Ghost key code
+ */
+static GHOST_TKey convertKey(int rawCode, unichar recvChar)
+{
+
+ //printf("\nrecvchar %c 0x%x",recvChar,recvChar);
+ switch (rawCode) {
+ /*Physical keycodes not used due to map changes in int'l keyboards
+ case kVK_ANSI_A: return GHOST_kKeyA;
+ case kVK_ANSI_B: return GHOST_kKeyB;
+ case kVK_ANSI_C: return GHOST_kKeyC;
+ case kVK_ANSI_D: return GHOST_kKeyD;
+ case kVK_ANSI_E: return GHOST_kKeyE;
+ case kVK_ANSI_F: return GHOST_kKeyF;
+ case kVK_ANSI_G: return GHOST_kKeyG;
+ case kVK_ANSI_H: return GHOST_kKeyH;
+ case kVK_ANSI_I: return GHOST_kKeyI;
+ case kVK_ANSI_J: return GHOST_kKeyJ;
+ case kVK_ANSI_K: return GHOST_kKeyK;
+ case kVK_ANSI_L: return GHOST_kKeyL;
+ case kVK_ANSI_M: return GHOST_kKeyM;
+ case kVK_ANSI_N: return GHOST_kKeyN;
+ case kVK_ANSI_O: return GHOST_kKeyO;
+ case kVK_ANSI_P: return GHOST_kKeyP;
+ case kVK_ANSI_Q: return GHOST_kKeyQ;
+ case kVK_ANSI_R: return GHOST_kKeyR;
+ case kVK_ANSI_S: return GHOST_kKeyS;
+ case kVK_ANSI_T: return GHOST_kKeyT;
+ case kVK_ANSI_U: return GHOST_kKeyU;
+ case kVK_ANSI_V: return GHOST_kKeyV;
+ case kVK_ANSI_W: return GHOST_kKeyW;
+ case kVK_ANSI_X: return GHOST_kKeyX;
+ case kVK_ANSI_Y: return GHOST_kKeyY;
+ case kVK_ANSI_Z: return GHOST_kKeyZ;*/
+
+ /* Numbers keys mapped to handle some int'l keyboard (e.g. French)*/
+ case kVK_ISO_Section: return GHOST_kKeyUnknown;
+ case kVK_ANSI_1: return GHOST_kKey1;
+ case kVK_ANSI_2: return GHOST_kKey2;
+ case kVK_ANSI_3: return GHOST_kKey3;
+ case kVK_ANSI_4: return GHOST_kKey4;
+ case kVK_ANSI_5: return GHOST_kKey5;
+ case kVK_ANSI_6: return GHOST_kKey6;
+ case kVK_ANSI_7: return GHOST_kKey7;
+ case kVK_ANSI_8: return GHOST_kKey8;
+ case kVK_ANSI_9: return GHOST_kKey9;
+ case kVK_ANSI_0: return GHOST_kKey0;
+
+ case kVK_ANSI_Keypad0: return GHOST_kKeyNumpad0;
+ case kVK_ANSI_Keypad1: return GHOST_kKeyNumpad1;
+ case kVK_ANSI_Keypad2: return GHOST_kKeyNumpad2;
+ case kVK_ANSI_Keypad3: return GHOST_kKeyNumpad3;
+ case kVK_ANSI_Keypad4: return GHOST_kKeyNumpad4;
+ case kVK_ANSI_Keypad5: return GHOST_kKeyNumpad5;
+ case kVK_ANSI_Keypad6: return GHOST_kKeyNumpad6;
+ case kVK_ANSI_Keypad7: return GHOST_kKeyNumpad7;
+ case kVK_ANSI_Keypad8: return GHOST_kKeyNumpad8;
+ case kVK_ANSI_Keypad9: return GHOST_kKeyNumpad9;
+ case kVK_ANSI_KeypadDecimal: return GHOST_kKeyNumpadPeriod;
+ case kVK_ANSI_KeypadEnter: return GHOST_kKeyNumpadEnter;
+ case kVK_ANSI_KeypadPlus: return GHOST_kKeyNumpadPlus;
+ case kVK_ANSI_KeypadMinus: return GHOST_kKeyNumpadMinus;
+ case kVK_ANSI_KeypadMultiply: return GHOST_kKeyNumpadAsterisk;
+ case kVK_ANSI_KeypadDivide: return GHOST_kKeyNumpadSlash;
+ case kVK_ANSI_KeypadClear: return GHOST_kKeyUnknown;
+
+ case kVK_F1: return GHOST_kKeyF1;
+ case kVK_F2: return GHOST_kKeyF2;
+ case kVK_F3: return GHOST_kKeyF3;
+ case kVK_F4: return GHOST_kKeyF4;
+ case kVK_F5: return GHOST_kKeyF5;
+ case kVK_F6: return GHOST_kKeyF6;
+ case kVK_F7: return GHOST_kKeyF7;
+ case kVK_F8: return GHOST_kKeyF8;
+ case kVK_F9: return GHOST_kKeyF9;
+ case kVK_F10: return GHOST_kKeyF10;
+ case kVK_F11: return GHOST_kKeyF11;
+ case kVK_F12: return GHOST_kKeyF12;
+ case kVK_F13: return GHOST_kKeyF13;
+ case kVK_F14: return GHOST_kKeyF14;
+ case kVK_F15: return GHOST_kKeyF15;
+ case kVK_F16: return GHOST_kKeyF16;
+ case kVK_F17: return GHOST_kKeyF17;
+ case kVK_F18: return GHOST_kKeyF18;
+ case kVK_F19: return GHOST_kKeyF19;
+ case kVK_F20: return GHOST_kKeyF20;
+
+ case kVK_UpArrow: return GHOST_kKeyUpArrow;
+ case kVK_DownArrow: return GHOST_kKeyDownArrow;
+ case kVK_LeftArrow: return GHOST_kKeyLeftArrow;
+ case kVK_RightArrow: return GHOST_kKeyRightArrow;
+
+ case kVK_Return: return GHOST_kKeyEnter;
+ case kVK_Delete: return GHOST_kKeyBackSpace;
+ case kVK_ForwardDelete: return GHOST_kKeyDelete;
+ case kVK_Escape: return GHOST_kKeyEsc;
+ case kVK_Tab: return GHOST_kKeyTab;
+ case kVK_Space: return GHOST_kKeySpace;
+
+ case kVK_Home: return GHOST_kKeyHome;
+ case kVK_End: return GHOST_kKeyEnd;
+ case kVK_PageUp: return GHOST_kKeyUpPage;
+ case kVK_PageDown: return GHOST_kKeyDownPage;
+
+ /*case kVK_ANSI_Minus: return GHOST_kKeyMinus;
+ case kVK_ANSI_Equal: return GHOST_kKeyEqual;
+ case kVK_ANSI_Comma: return GHOST_kKeyComma;
+ case kVK_ANSI_Period: return GHOST_kKeyPeriod;
+ case kVK_ANSI_Slash: return GHOST_kKeySlash;
+ case kVK_ANSI_Semicolon: return GHOST_kKeySemicolon;
+ case kVK_ANSI_Quote: return GHOST_kKeyQuote;
+ case kVK_ANSI_Backslash: return GHOST_kKeyBackslash;
+ case kVK_ANSI_LeftBracket: return GHOST_kKeyLeftBracket;
+ case kVK_ANSI_RightBracket: return GHOST_kKeyRightBracket;
+ case kVK_ANSI_Grave: return GHOST_kKeyAccentGrave;*/
+
+ case kVK_VolumeUp:
+ case kVK_VolumeDown:
+ case kVK_Mute:
+ return GHOST_kKeyUnknown;
+
+ default:
+ /*Then detect on character value for "remappable" keys in int'l keyboards*/
+ if ((recvChar >= 'A') && (recvChar <= 'Z')) {
+ return (GHOST_TKey) (recvChar - 'A' + GHOST_kKeyA);
+ } else if ((recvChar >= 'a') && (recvChar <= 'z')) {
+ return (GHOST_TKey) (recvChar - 'a' + GHOST_kKeyA);
+ } else
+ switch (recvChar) {
+ case '-': return GHOST_kKeyMinus;
+ case '=': return GHOST_kKeyEqual;
+ case ',': return GHOST_kKeyComma;
+ case '.': return GHOST_kKeyPeriod;
+ case '/': return GHOST_kKeySlash;
+ case ';': return GHOST_kKeySemicolon;
+ case '\'': return GHOST_kKeyQuote;
+ case '\\': return GHOST_kKeyBackslash;
+ case '[': return GHOST_kKeyLeftBracket;
+ case ']': return GHOST_kKeyRightBracket;
+ case '`': return GHOST_kKeyAccentGrave;
+ default:
+ return GHOST_kKeyUnknown;
+ }
+ }
+ return GHOST_kKeyUnknown;
+}
+
+/* MacOSX returns a Roman charset with kEventParamKeyMacCharCodes
+ * as defined here: http://developer.apple.com/documentation/mac/Text/Text-516.html
+ * I am not sure how international this works...
+ * For cross-platform convention, we'll use the Latin ascii set instead.
+ * As defined at: http://www.ramsch.org/martin/uni/fmi-hp/iso8859-1.html
+ *
+ */
+static unsigned char convertRomanToLatin(unsigned char ascii)
+{
+
+ if(ascii<128) return ascii;
+
+ switch(ascii) {
+ case 128: return 142;
+ case 129: return 143;
+ case 130: return 128;
+ case 131: return 201;
+ case 132: return 209;
+ case 133: return 214;
+ case 134: return 220;
+ case 135: return 225;
+ case 136: return 224;
+ case 137: return 226;
+ case 138: return 228;
+ case 139: return 227;
+ case 140: return 229;
+ case 141: return 231;
+ case 142: return 233;
+ case 143: return 232;
+ case 144: return 234;
+ case 145: return 235;
+ case 146: return 237;
+ case 147: return 236;
+ case 148: return 238;
+ case 149: return 239;
+ case 150: return 241;
+ case 151: return 243;
+ case 152: return 242;
+ case 153: return 244;
+ case 154: return 246;
+ case 155: return 245;
+ case 156: return 250;
+ case 157: return 249;
+ case 158: return 251;
+ case 159: return 252;
+ case 160: return 0;
+ case 161: return 176;
+ case 162: return 162;
+ case 163: return 163;
+ case 164: return 167;
+ case 165: return 183;
+ case 166: return 182;
+ case 167: return 223;
+ case 168: return 174;
+ case 169: return 169;
+ case 170: return 174;
+ case 171: return 180;
+ case 172: return 168;
+ case 173: return 0;
+ case 174: return 198;
+ case 175: return 216;
+ case 176: return 0;
+ case 177: return 177;
+ case 178: return 0;
+ case 179: return 0;
+ case 180: return 165;
+ case 181: return 181;
+ case 182: return 0;
+ case 183: return 0;
+ case 184: return 215;
+ case 185: return 0;
+ case 186: return 0;
+ case 187: return 170;
+ case 188: return 186;
+ case 189: return 0;
+ case 190: return 230;
+ case 191: return 248;
+ case 192: return 191;
+ case 193: return 161;
+ case 194: return 172;
+ case 195: return 0;
+ case 196: return 0;
+ case 197: return 0;
+ case 198: return 0;
+ case 199: return 171;
+ case 200: return 187;
+ case 201: return 201;
+ case 202: return 0;
+ case 203: return 192;
+ case 204: return 195;
+ case 205: return 213;
+ case 206: return 0;
+ case 207: return 0;
+ case 208: return 0;
+ case 209: return 0;
+ case 210: return 0;
+
+ case 214: return 247;
+
+ case 229: return 194;
+ case 230: return 202;
+ case 231: return 193;
+ case 232: return 203;
+ case 233: return 200;
+ case 234: return 205;
+ case 235: return 206;
+ case 236: return 207;
+ case 237: return 204;
+ case 238: return 211;
+ case 239: return 212;
+ case 240: return 0;
+ case 241: return 210;
+ case 242: return 218;
+ case 243: return 219;
+ case 244: return 217;
+ case 245: return 0;
+ case 246: return 0;
+ case 247: return 0;
+ case 248: return 0;
+ case 249: return 0;
+ case 250: return 0;
+
+
+ default: return 0;
+ }
+
+}
+
+#define FIRSTFILEBUFLG 512
+static bool g_hasFirstFile = false;
+static char g_firstFileBuf[512];
+
+//TODO:Need to investigate this. Function called too early in creator.c to have g_hasFirstFile == true
+extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) {
+ if (g_hasFirstFile) {
+ strncpy(buf, g_firstFileBuf, FIRSTFILEBUFLG - 1);
+ buf[FIRSTFILEBUFLG - 1] = '\0';
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+#pragma mark Cocoa objects
+
+/**
+ * CocoaAppDelegate
+ * ObjC object to capture applicationShouldTerminate, and send quit event
+ **/
+@interface CocoaAppDelegate : NSObject {
+ GHOST_SystemCocoa *systemCocoa;
+}
+-(void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa;
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
+- (void)applicationWillTerminate:(NSNotification *)aNotification;
+@end
+
+@implementation CocoaAppDelegate : NSObject
+-(void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa
+{
+ systemCocoa = sysCocoa;
+}
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
+{
+ //TODO: implement graceful termination through Cocoa mechanism to avoid session log off to be cancelled
+ //Note that Cmd+Q is already handled by keyhandler
+ if (systemCocoa->handleQuitRequest() == GHOST_kExitNow)
+ return NSTerminateCancel;//NSTerminateNow;
+ else
+ return NSTerminateCancel;
+}
+
+// To avoid cancelling a log off process, we must use Cocoa termination process
+// And this function is the only chance to perform clean up
+// So WM_exit needs to be called directly, as the event loop will never run before termination
+- (void)applicationWillTerminate:(NSNotification *)aNotification
+{
+ /*G.afbreek = 0; //Let Cocoa perform the termination at the end
+ WM_exit(C);*/
+}
+@end
+
+
+
+#pragma mark initialization/finalization
+
+
+GHOST_SystemCocoa::GHOST_SystemCocoa()
+{
+ m_modifierMask =0;
+ m_pressedMouseButtons =0;
+ m_displayManager = new GHOST_DisplayManagerCocoa ();
+ GHOST_ASSERT(m_displayManager, "GHOST_SystemCocoa::GHOST_SystemCocoa(): m_displayManager==0\n");
+ m_displayManager->initialize();
+
+ //NSEvent timeStamp is given in system uptime, state start date is boot time
+ //FIXME : replace by Cocoa equivalent
+ int mib[2];
+ struct timeval boottime;
+ size_t len;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_BOOTTIME;
+ len = sizeof(struct timeval);
+
+ sysctl(mib, 2, &boottime, &len, NULL, 0);
+ m_start_time = ((boottime.tv_sec*1000)+(boottime.tv_usec/1000));
+
+ m_ignoreWindowSizedMessages = false;
+}
+
+GHOST_SystemCocoa::~GHOST_SystemCocoa()
+{
+}
+
+
+GHOST_TSuccess GHOST_SystemCocoa::init()
+{
+
+ GHOST_TSuccess success = GHOST_System::init();
+ if (success) {
+ //ProcessSerialNumber psn;
+
+ //Carbon stuff to move window & menu to foreground
+ /*if (!GetCurrentProcess(&psn)) {
+ TransformProcessType(&psn, kProcessTransformToForegroundApplication);
+ SetFrontProcess(&psn);
+ }*/
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ if (NSApp == nil) {
+ [NSApplication sharedApplication];
+
+ if ([NSApp mainMenu] == nil) {
+ NSMenu *mainMenubar = [[NSMenu alloc] init];
+ NSMenuItem *menuItem;
+ NSMenu *windowMenu;
+ NSMenu *appMenu;
+
+ //Create the application menu
+ appMenu = [[NSMenu alloc] initWithTitle:@"Blender"];
+
+ [appMenu addItemWithTitle:@"About Blender" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
+ [appMenu addItem:[NSMenuItem separatorItem]];
+
+ menuItem = [appMenu addItemWithTitle:@"Hide Blender" action:@selector(hide:) keyEquivalent:@"h"];
+ [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+
+ menuItem = [appMenu addItemWithTitle:@"Hide others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
+ [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)];
+
+ [appMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
+
+ menuItem = [appMenu addItemWithTitle:@"Quit Blender" action:@selector(terminate:) keyEquivalent:@"q"];
+ [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+
+ menuItem = [[NSMenuItem alloc] init];
+ [menuItem setSubmenu:appMenu];
+
+ [mainMenubar addItem:menuItem];
+ [menuItem release];
+ [NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu]; //Needed for 10.5
+ [appMenu release];
+
+ //Create the window menu
+ windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
+
+ menuItem = [windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
+ [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
+
+ [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
+
+ menuItem = [[NSMenuItem alloc] init];
+ [menuItem setSubmenu:windowMenu];
+
+ [mainMenubar addItem:menuItem];
+ [menuItem release];
+
+ [NSApp setMainMenu:mainMenubar];
+ [NSApp setWindowsMenu:windowMenu];
+ [windowMenu release];
+ }
+ [NSApp finishLaunching];
+ }
+ if ([NSApp delegate] == nil) {
+ CocoaAppDelegate *appDelegate = [[CocoaAppDelegate alloc] init];
+ [appDelegate setSystemCocoa:this];
+ [NSApp setDelegate:appDelegate];
+ }
+
+ [pool drain];
+ }
+ return success;
+}
+
+
+#pragma mark window management
+
+GHOST_TUns64 GHOST_SystemCocoa::getMilliSeconds() const
+{
+ //Cocoa equivalent exists in 10.6 ([[NSProcessInfo processInfo] systemUptime])
+ int mib[2];
+ struct timeval boottime;
+ size_t len;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_BOOTTIME;
+ len = sizeof(struct timeval);
+
+ sysctl(mib, 2, &boottime, &len, NULL, 0);
+
+ return ((boottime.tv_sec*1000)+(boottime.tv_usec/1000));
+}
+
+
+GHOST_TUns8 GHOST_SystemCocoa::getNumDisplays() const
+{
+ //Note that OS X supports monitor hot plug
+ // We do not support multiple monitors at the moment
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ GHOST_TUns8 count = [[NSScreen screens] count];
+
+ [pool drain];
+ return count;
+}
+
+
+void GHOST_SystemCocoa::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ //Get visible frame, that is frame excluding dock and top menu bar
+ NSRect frame = [[NSScreen mainScreen] visibleFrame];
+
+ //Returns max window contents (excluding title bar...)
+ NSRect contentRect = [NSWindow contentRectForFrameRect:frame
+ styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)];
+
+ width = contentRect.size.width;
+ height = contentRect.size.height;
+
+ [pool drain];
+}
+
+
+GHOST_IWindow* GHOST_SystemCocoa::createWindow(
+ const STR_String& title,
+ GHOST_TInt32 left,
+ GHOST_TInt32 top,
+ GHOST_TUns32 width,
+ GHOST_TUns32 height,
+ GHOST_TWindowState state,
+ GHOST_TDrawingContextType type,
+ bool stereoVisual,
+ const GHOST_TEmbedderWindowID parentWindow
+)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ GHOST_IWindow* window = 0;
+
+ //Get the available rect for including window contents
+ NSRect frame = [[NSScreen mainScreen] visibleFrame];
+ NSRect contentRect = [NSWindow contentRectForFrameRect:frame
+ styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)];
+
+ //Ensures window top left is inside this available rect
+ left = left > contentRect.origin.x ? left : contentRect.origin.x;
+ top = top > contentRect.origin.y ? top : contentRect.origin.y;
+
+ window = new GHOST_WindowCocoa (this, title, left, top, width, height, state, type);
+
+ if (window) {
+ if (window->getValid()) {
+ // Store the pointer to the window
+ GHOST_ASSERT(m_windowManager, "m_windowManager not initialized");
+ m_windowManager->addWindow(window);
+ m_windowManager->setActiveWindow(window);
+ //Need to tell window manager the new window is the active one (Cocoa does not send the event activate upon window creation)
+ pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window));
+ pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window));
+
+ }
+ else {
+ GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n");
+ delete window;
+ window = 0;
+ }
+ }
+ else {
+ GHOST_PRINT("GHOST_SystemCocoa::createWindow(): could not create window\n");
+ }
+ [pool drain];
+ return window;
+}
+
+GHOST_TSuccess GHOST_SystemCocoa::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, const bool stereoVisual)
+{
+ GHOST_IWindow* currentWindow = m_windowManager->getActiveWindow();
+
+ *window = currentWindow;
+
+ return currentWindow->setState(GHOST_kWindowStateFullScreen);
+}
+
+GHOST_TSuccess GHOST_SystemCocoa::endFullScreen(void)
+{
+ GHOST_IWindow* currentWindow = m_windowManager->getActiveWindow();
+
+ return currentWindow->setState(GHOST_kWindowStateNormal);
+}
+
+
+
+
+GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
+{
+ NSPoint mouseLoc = [NSEvent mouseLocation];
+
+ // Returns the mouse location in screen coordinates
+ x = (GHOST_TInt32)mouseLoc.x;
+ y = (GHOST_TInt32)mouseLoc.y;
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const
+{
+ float xf=(float)x, yf=(float)y;
+
+ //Quartz Display Services uses the old coordinates (top left origin)
+ yf = [[NSScreen mainScreen] frame].size.height -yf;
+
+ //CGAssociateMouseAndMouseCursorPosition(false);
+ CGWarpMouseCursorPosition(CGPointMake(xf, yf));
+ //CGAssociateMouseAndMouseCursorPosition(true);
+
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_SystemCocoa::getModifierKeys(GHOST_ModifierKeys& keys) const
+{
+ unsigned int modifiers = [[NSApp currentEvent] modifierFlags];
+ //Direct query to modifierFlags can be used in 10.6
+
+ keys.set(GHOST_kModifierKeyCommand, (modifiers & NSCommandKeyMask) ? true : false);
+ keys.set(GHOST_kModifierKeyLeftAlt, (modifiers & NSAlternateKeyMask) ? true : false);
+ keys.set(GHOST_kModifierKeyLeftShift, (modifiers & NSShiftKeyMask) ? true : false);
+ keys.set(GHOST_kModifierKeyLeftControl, (modifiers & NSControlKeyMask) ? true : false);
+
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_SystemCocoa::getButtons(GHOST_Buttons& buttons) const
+{
+ buttons.clear();
+ buttons.set(GHOST_kButtonMaskLeft, m_pressedMouseButtons & GHOST_kButtonMaskLeft);
+ buttons.set(GHOST_kButtonMaskRight, m_pressedMouseButtons & GHOST_kButtonMaskRight);
+ buttons.set(GHOST_kButtonMaskMiddle, m_pressedMouseButtons & GHOST_kButtonMaskMiddle);
+ buttons.set(GHOST_kButtonMaskButton4, m_pressedMouseButtons & GHOST_kButtonMaskButton4);
+ buttons.set(GHOST_kButtonMaskButton5, m_pressedMouseButtons & GHOST_kButtonMaskButton5);
+ return GHOST_kSuccess;
+}
+
+
+
+#pragma mark Event handlers
+
+/**
+ * The event queue polling function
+ */
+bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
+{
+ bool anyProcessed = false;
+ NSEvent *event;
+
+ // SetMouseCoalescingEnabled(false, NULL);
+ //TODO : implement timer ??
+
+ /*do {
+ GHOST_TimerManager* timerMgr = getTimerManager();
+
+ if (waitForEvent) {
+ GHOST_TUns64 next = timerMgr->nextFireTime();
+ double timeOut;
+
+ if (next == GHOST_kFireTimeNever) {
+ timeOut = kEventDurationForever;
+ } else {
+ timeOut = (double)(next - getMilliSeconds())/1000.0;
+ if (timeOut < 0.0)
+ timeOut = 0.0;
+ }
+
+ ::ReceiveNextEvent(0, NULL, timeOut, false, &event);
+ }
+
+ if (timerMgr->fireTimers(getMilliSeconds())) {
+ anyProcessed = true;
+ }
+
+ if (getFullScreen()) {
+ // Check if the full-screen window is dirty
+ GHOST_IWindow* window = m_windowManager->getFullScreenWindow();
+ if (((GHOST_WindowCarbon*)window)->getFullScreenDirty()) {
+ pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) );
+ anyProcessed = true;
+ }
+ }*/
+
+ do {
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:[NSDate distantPast]
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+ if (event==nil) {
+ [pool drain];
+ break;
+ }
+
+ anyProcessed = true;
+
+ switch ([event type]) {
+ case NSKeyDown:
+ case NSKeyUp:
+ case NSFlagsChanged:
+ handleKeyEvent(event);
+
+ /* Support system-wide keyboard shortcuts, like Exposé, ...) =>included in always NSApp sendEvent */
+ /* if (([event modifierFlags] & NSCommandKeyMask) || [event type] == NSFlagsChanged) {
+ [NSApp sendEvent:event];
+ }*/
+ break;
+
+ case NSLeftMouseDown:
+ case NSLeftMouseUp:
+ case NSRightMouseDown:
+ case NSRightMouseUp:
+ case NSMouseMoved:
+ case NSLeftMouseDragged:
+ case NSRightMouseDragged:
+ case NSScrollWheel:
+ case NSOtherMouseDown:
+ case NSOtherMouseUp:
+ case NSOtherMouseDragged:
+ handleMouseEvent(event);
+ break;
+
+ case NSTabletPoint:
+ case NSTabletProximity:
+ handleTabletEvent(event,[event type]);
+ break;
+
+ /* Trackpad features, will need OS X 10.6 for implementation
+ case NSEventTypeGesture:
+ case NSEventTypeMagnify:
+ case NSEventTypeSwipe:
+ case NSEventTypeRotate:
+ case NSEventTypeBeginGesture:
+ case NSEventTypeEndGesture:
+ break; */
+
+ /*Unused events
+ NSMouseEntered = 8,
+ NSMouseExited = 9,
+ NSAppKitDefined = 13,
+ NSSystemDefined = 14,
+ NSApplicationDefined = 15,
+ NSPeriodic = 16,
+ NSCursorUpdate = 17,*/
+
+ default:
+ break;
+ }
+ //Resend event to NSApp to ensure Mac wide events are handled
+ [NSApp sendEvent:event];
+ [pool drain];
+ } while (event!= nil);
+ //} while (waitForEvent && !anyProcessed); Needed only for timer implementation
+
+
+
+ return anyProcessed;
+}
+
+//Note: called from NSWindow delegate
+GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType, GHOST_WindowCocoa* window)
+{
+ if (!validWindow(window)) {
+ return GHOST_kFailure;
+ }
+ switch(eventType)
+ {
+ case GHOST_kEventWindowClose:
+ pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window) );
+ break;
+ case GHOST_kEventWindowActivate:
+ m_windowManager->setActiveWindow(window);
+ window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
+ pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window) );
+ break;
+ case GHOST_kEventWindowDeactivate:
+ m_windowManager->setWindowInactive(window);
+ pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window) );
+ break;
+ case GHOST_kEventWindowUpdate:
+ pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) );
+ break;
+ case GHOST_kEventWindowSize:
+ if (!m_ignoreWindowSizedMessages)
+ {
+ window->updateDrawingContext();
+ pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
+ }
+ break;
+ default:
+ return GHOST_kFailure;
+ break;
+ }
+ return GHOST_kSuccess;
+}
+
+GHOST_TUns8 GHOST_SystemCocoa::handleQuitRequest()
+{
+ //Check open windows if some changes are not saved
+ if (m_windowManager->getAnyModifiedState())
+ {
+ int shouldQuit = NSRunAlertPanel(@"Exit Blender", @"Some changes have not been saved. Do you really want to quit ?",
+ @"Cancel", @"Quit anyway", nil);
+ if (shouldQuit == NSAlertAlternateReturn)
+ {
+ pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventQuit, NULL) );
+ return GHOST_kExitNow;
+ }
+ }
+ else {
+ pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventQuit, NULL) );
+ return GHOST_kExitNow;
+ }
+
+ return GHOST_kExitCancel;
+}
+
+
+GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventType)
+{
+ NSEvent *event = (NSEvent *)eventPtr;
+ GHOST_IWindow* window = m_windowManager->getActiveWindow();
+ GHOST_TabletData& ct=((GHOST_WindowCocoa*)window)->GetCocoaTabletData();
+
+ switch (eventType) {
+ case NSTabletPoint:
+ ct.Pressure = [event tangentialPressure];
+ ct.Xtilt = [event tilt].x;
+ ct.Ytilt = [event tilt].y;
+ break;
+
+ case NSTabletProximity:
+ ct.Pressure = 0;
+ ct.Xtilt = 0;
+ ct.Ytilt = 0;
+ if ([event isEnteringProximity])
+ {
+ //pointer is entering tablet area proximity
+ switch ([event pointingDeviceType]) {
+ case NSPenPointingDevice:
+ ct.Active = GHOST_kTabletModeStylus;
+ break;
+ case NSEraserPointingDevice:
+ ct.Active = GHOST_kTabletModeEraser;
+ break;
+ case NSCursorPointingDevice:
+ case NSUnknownPointingDevice:
+ default:
+ ct.Active = GHOST_kTabletModeNone;
+ break;
+ }
+ } else {
+ // pointer is leaving - return to mouse
+ ct.Active = GHOST_kTabletModeNone;
+ }
+ break;
+
+ default:
+ GHOST_ASSERT(FALSE,"GHOST_SystemCocoa::handleTabletEvent : unknown event received");
+ return GHOST_kFailure;
+ break;
+ }
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
+{
+ NSEvent *event = (NSEvent *)eventPtr;
+ GHOST_Window* window = (GHOST_Window*)m_windowManager->getActiveWindow();
+
+ if (!window) {
+ return GHOST_kFailure;
+ }
+
+ switch ([event type])
+ {
+ case NSLeftMouseDown:
+ case NSRightMouseDown:
+ case NSOtherMouseDown:
+ pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonDown, window, convertButton([event buttonNumber])));
+ //Handle tablet events combined with mouse events
+ switch ([event subtype]) {
+ case NX_SUBTYPE_TABLET_POINT:
+ handleTabletEvent(eventPtr, NSTabletPoint);
+ break;
+ case NX_SUBTYPE_TABLET_PROXIMITY:
+ handleTabletEvent(eventPtr, NSTabletProximity);
+ break;
+ default:
+ //No tablet event included : do nothing
+ break;
+ }
+ break;
+
+ case NSLeftMouseUp:
+ case NSRightMouseUp:
+ case NSOtherMouseUp:
+ pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonUp, window, convertButton([event buttonNumber])));
+ //Handle tablet events combined with mouse events
+ switch ([event subtype]) {
+ case NX_SUBTYPE_TABLET_POINT:
+ handleTabletEvent(eventPtr, NSTabletPoint);
+ break;
+ case NX_SUBTYPE_TABLET_PROXIMITY:
+ handleTabletEvent(eventPtr, NSTabletProximity);
+ break;
+ default:
+ //No tablet event included : do nothing
+ break;
+ }
+ break;
+
+ case NSLeftMouseDragged:
+ case NSRightMouseDragged:
+ case NSOtherMouseDragged:
+ //Handle tablet events combined with mouse events
+ switch ([event subtype]) {
+ case NX_SUBTYPE_TABLET_POINT:
+ handleTabletEvent(eventPtr, NSTabletPoint);
+ break;
+ case NX_SUBTYPE_TABLET_PROXIMITY:
+ handleTabletEvent(eventPtr, NSTabletProximity);
+ break;
+ default:
+ //No tablet event included : do nothing
+ break;
+ }
+ case NSMouseMoved:
+ {
+ if(window->getCursorWarp()) {
+ GHOST_TInt32 x_warp, y_warp, x_accum, y_accum;
+
+ window->getCursorWarpPos(x_warp, y_warp);
+
+ window->getCursorWarpAccum(x_accum, y_accum);
+ x_accum += [event deltaX];
+ y_accum += -[event deltaY]; //Strange Apple implementation (inverted coordinates for the deltaY) ...
+ window->setCursorWarpAccum(x_accum, y_accum);
+
+ pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, x_warp+x_accum, y_warp+y_accum));
+ }
+ else { //Normal cursor operation: send mouse position in window
+ NSPoint mousePos = [event locationInWindow];
+ pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, mousePos.x, mousePos.y));
+ window->setCursorWarpAccum(0, 0); //Mouse motion occured between two cursor warps, so we can reset the delta counter
+ }
+ break;
+ }
+
+ case NSScrollWheel:
+ {
+ GHOST_TInt32 delta;
+
+ double deltaF = [event deltaY];
+ if (deltaF == 0.0) break; //discard trackpad delta=0 events
+
+ delta = deltaF > 0.0 ? 1 : -1;
+ pushEvent(new GHOST_EventWheel([event timestamp], window, delta));
+ }
+ break;
+
+ default:
+ return GHOST_kFailure;
+ break;
+ }
+
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
+{
+ NSEvent *event = (NSEvent *)eventPtr;
+ GHOST_IWindow* window = m_windowManager->getActiveWindow();
+ unsigned int modifiers;
+ NSString *characters;
+ GHOST_TKey keyCode;
+ unsigned char ascii;
+
+ /* Can happen, very rarely - seems to only be when command-H makes
+ * the window go away and we still get an HKey up.
+ */
+ if (!window) {
+ printf("\nW failure");
+ return GHOST_kFailure;
+ }
+
+ switch ([event type]) {
+ case NSKeyDown:
+ case NSKeyUp:
+ characters = [event characters];
+ if ([characters length]) { //Check for dead keys
+ keyCode = convertKey([event keyCode],
+ [[event charactersIgnoringModifiers] characterAtIndex:0]);
+ ascii= convertRomanToLatin((char)[characters characterAtIndex:0]);
+ } else {
+ keyCode = convertKey([event keyCode],0);
+ ascii= 0;
+ }
+
+
+ if ((keyCode == GHOST_kKeyQ) && (m_modifierMask & NSCommandKeyMask))
+ break; //Cmd-Q is directly handled by Cocoa
+
+ if ([event type] == NSKeyDown) {
+ pushEvent( new GHOST_EventKey([event timestamp], GHOST_kEventKeyDown, window, keyCode, ascii) );
+ //printf("\nKey pressed keyCode=%u ascii=%i %c",keyCode,ascii,ascii);
+ } else {
+ pushEvent( new GHOST_EventKey([event timestamp], GHOST_kEventKeyUp, window, keyCode, ascii) );
+ }
+ break;
+
+ case NSFlagsChanged:
+ modifiers = [event modifierFlags];
+ if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) {
+ pushEvent( new GHOST_EventKey([event timestamp], (modifiers & NSShiftKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) );
+ }
+ if ((modifiers & NSControlKeyMask) != (m_modifierMask & NSControlKeyMask)) {
+ pushEvent( new GHOST_EventKey([event timestamp], (modifiers & NSControlKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl) );
+ }
+ if ((modifiers & NSAlternateKeyMask) != (m_modifierMask & NSAlternateKeyMask)) {
+ pushEvent( new GHOST_EventKey([event timestamp], (modifiers & NSAlternateKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) );
+ }
+ if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) {
+ pushEvent( new GHOST_EventKey([event timestamp], (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyCommand) );
+ }
+
+ m_modifierMask = modifiers;
+ break;
+
+ default:
+ return GHOST_kFailure;
+ break;
+ }
+
+ return GHOST_kSuccess;
+}
+
+
+
+#pragma mark Clipboard get/set
+
+GHOST_TUns8* GHOST_SystemCocoa::getClipboard(bool selection) const
+{
+ GHOST_TUns8 * temp_buff;
+ size_t pastedTextSize;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
+
+ if (pasteBoard == nil) {
+ [pool drain];
+ return NULL;
+ }
+
+ NSArray *supportedTypes =
+ [NSArray arrayWithObjects: @"public.utf8-plain-text", nil];
+
+ NSString *bestType = [[NSPasteboard generalPasteboard]
+ availableTypeFromArray:supportedTypes];
+
+ if (bestType == nil) {
+ [pool drain];
+ return NULL;
+ }
+
+ NSString * textPasted = [pasteBoard stringForType:@"public.utf8-plain-text"];
+
+ if (textPasted == nil) {
+ [pool drain];
+ return NULL;
+ }
+
+ pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+
+ temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1);
+
+ if (temp_buff == NULL) {
+ [pool drain];
+ return NULL;
+ }
+
+ strncpy((char*)temp_buff, [textPasted UTF8String], pastedTextSize);
+
+ temp_buff[pastedTextSize] = '\0';
+
+ [pool drain];
+
+ if(temp_buff) {
+ return temp_buff;
+ } else {
+ return NULL;
+ }
+}
+
+void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const
+{
+ NSString *textToCopy;
+
+ if(selection) {return;} // for copying the selection, used on X11
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
+
+ if (pasteBoard == nil) {
+ [pool drain];
+ return;
+ }
+
+ NSArray *supportedTypes = [NSArray arrayWithObject:@"public.utf8-plain-text"];
+
+ [pasteBoard declareTypes:supportedTypes owner:nil];
+
+ textToCopy = [NSString stringWithUTF8String:buffer];
+
+ [pasteBoard setString:textToCopy forType:@"public.utf8-plain-text"];
+
+ [pool drain];
+}
+
+#pragma mark Carbon stuff to remove
+
+#ifdef WITH_CARBON
+
+
+OSErr GHOST_SystemCarbon::sAEHandlerLaunch(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
+{
+ //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
+
+ return noErr;
+}
+
+OSErr GHOST_SystemCarbon::sAEHandlerOpenDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
+{
+ //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
+ AEDescList docs;
+ SInt32 ndocs;
+ OSErr err;
+
+ err = AEGetParamDesc(event, keyDirectObject, typeAEList, &docs);
+ if (err != noErr) return err;
+
+ err = AECountItems(&docs, &ndocs);
+ if (err==noErr) {
+ int i;
+
+ for (i=0; i<ndocs; i++) {
+ FSSpec fss;
+ AEKeyword kwd;
+ DescType actType;
+ Size actSize;
+
+ err = AEGetNthPtr(&docs, i+1, typeFSS, &kwd, &actType, &fss, sizeof(fss), &actSize);
+ if (err!=noErr)
+ break;
+
+ if (i==0) {
+ FSRef fsref;
+
+ if (FSpMakeFSRef(&fss, &fsref)!=noErr)
+ break;
+ if (FSRefMakePath(&fsref, (UInt8*) g_firstFileBuf, sizeof(g_firstFileBuf))!=noErr)
+ break;
+
+ g_hasFirstFile = true;
+ }
+ }
+ }
+
+ AEDisposeDesc(&docs);
+
+ return err;
+}
+
+OSErr GHOST_SystemCarbon::sAEHandlerPrintDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
+{
+ //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
+
+ return noErr;
+}
+
+OSErr GHOST_SystemCarbon::sAEHandlerQuit(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
+{
+ GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
+
+ sys->pushEvent( new GHOST_Event(sys->getMilliSeconds(), GHOST_kEventQuit, NULL) );
+
+ return noErr;
+}
+#endif \ No newline at end of file
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h
new file mode 100644
index 00000000000..4037ebafc64
--- /dev/null
+++ b/intern/ghost/intern/GHOST_WindowCocoa.h
@@ -0,0 +1,295 @@
+/**
+ * $Id: GHOST_WindowCocoa.h 23789 2009-10-12 16:51:36Z damien78 $
+ * ***** 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 *****
+ */
+/**
+ * @file GHOST_WindowCocoa.h
+ * Declaration of GHOST_WindowCocoa class.
+ */
+
+#ifndef _GHOST_WINDOW_COCOA_H_
+#define _GHOST_WINDOW_COCOA_H_
+
+#ifndef __APPLE__
+#error Apple OSX only!
+#endif // __APPLE__
+
+#include "GHOST_Window.h"
+#include "STR_String.h"
+
+class GHOST_SystemCocoa;
+
+/**
+ * Window on Mac OSX/Cocoa.
+ * Carbon windows have a size widget in the lower right corner of the window.
+ * To force it to be visible, the height of the client rectangle is reduced so
+ * that applications do not draw in that area. GHOST will manage that area
+ * which is called the gutter.
+ * When OpenGL contexts are active, GHOST will use AGL_BUFFER_RECT to prevent
+ * OpenGL drawing outside the reduced client rectangle.
+ * @author Maarten Gribnau
+ * @date May 23, 2001
+ */
+class GHOST_WindowCocoa : public GHOST_Window {
+public:
+ /**
+ * Constructor.
+ * Creates a new window and opens it.
+ * To check if the window was created properly, use the getValid() method.
+ * @param systemCocoa The associated system class to forward events to
+ * @param title The text shown in the title bar of the window.
+ * @param left The coordinate of the left edge of the window.
+ * @param top The coordinate of the top edge of the window.
+ * @param width The width the window.
+ * @param height The height the window.
+ * @param state The state the window is initially opened with.
+ * @param type The type of drawing context installed in this window.
+ * @param stereoVisual Stereo visual for quad buffered stereo.
+ */
+ GHOST_WindowCocoa(
+ GHOST_SystemCocoa *systemCocoa,
+ const STR_String& title,
+ GHOST_TInt32 left,
+ GHOST_TInt32 top,
+ GHOST_TUns32 width,
+ GHOST_TUns32 height,
+ GHOST_TWindowState state,
+ GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
+ const bool stereoVisual = false
+ );
+
+ /**
+ * Destructor.
+ * Closes the window and disposes resources allocated.
+ */
+ virtual ~GHOST_WindowCocoa();
+
+ /**
+ * Returns indication as to whether the window is valid.
+ * @return The validity of the window.
+ */
+ virtual bool getValid() const;
+
+ /**
+ * Sets the title displayed in the title bar.
+ * @param title The title to display in the title bar.
+ */
+ virtual void setTitle(const STR_String& title);
+
+ /**
+ * Returns the title displayed in the title bar.
+ * @param title The title displayed in the title bar.
+ */
+ virtual void getTitle(STR_String& title) const;
+
+ /**
+ * Returns the window rectangle dimensions.
+ * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen.
+ * @param bounds The bounding rectangle of the window.
+ */
+ virtual void getWindowBounds(GHOST_Rect& bounds) const;
+
+ /**
+ * Returns the client rectangle dimensions.
+ * The left and top members of the rectangle are always zero.
+ * @param bounds The bounding rectangle of the cleient area of the window.
+ */
+ virtual void getClientBounds(GHOST_Rect& bounds) const;
+
+ /**
+ * Resizes client rectangle width.
+ * @param width The new width of the client area of the window.
+ */
+ virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width);
+
+ /**
+ * Resizes client rectangle height.
+ * @param height The new height of the client area of the window.
+ */
+ virtual GHOST_TSuccess setClientHeight(GHOST_TUns32 height);
+
+ /**
+ * Resizes client rectangle.
+ * @param width The new width of the client area of the window.
+ * @param height The new height of the client area of the window.
+ */
+ virtual GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height);
+
+ /**
+ * Returns the state of the window (normal, minimized, maximized).
+ * @return The state of the window.
+ */
+ virtual GHOST_TWindowState getState() const;
+
+ /**
+ * Sets the window "modified" status, indicating unsaved changes
+ * @param isUnsavedChanges Unsaved changes or not
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess setModifiedState(bool isUnsavedChanges);
+
+ /**
+ * Converts a point in screen coordinates to client rectangle coordinates
+ * @param inX The x-coordinate on the screen.
+ * @param inY The y-coordinate on the screen.
+ * @param outX The x-coordinate in the client rectangle.
+ * @param outY The y-coordinate in the client rectangle.
+ */
+ virtual void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const;
+
+ /**
+ * Converts a point in screen coordinates to client rectangle coordinates
+ * @param inX The x-coordinate in the client rectangle.
+ * @param inY The y-coordinate in the client rectangle.
+ * @param outX The x-coordinate on the screen.
+ * @param outY The y-coordinate on the screen.
+ */
+ virtual void clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const;
+
+ /**
+ * Sets the state of the window (normal, minimized, maximized).
+ * @param state The state of the window.
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess setState(GHOST_TWindowState state);
+
+ /**
+ * Sets the order of the window (bottom, top).
+ * @param order The order of the window.
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order);
+
+ /**
+ * Swaps front and back buffers of a window.
+ * @return A boolean success indicator.
+ */
+ virtual GHOST_TSuccess swapBuffers();
+
+ /**
+ * Updates the drawing context of this window. Needed
+ * whenever the window is changed.
+ * @return Indication of success.
+ */
+ GHOST_TSuccess updateDrawingContext();
+
+ /**
+ * Activates the drawing context of this window.
+ * @return A boolean success indicator.
+ */
+ virtual GHOST_TSuccess activateDrawingContext();
+
+ virtual void loadCursor(bool visible, GHOST_TStandardCursor cursor) const;
+
+
+ const GHOST_TabletData* GetTabletData()
+ { return &m_tablet; }
+
+ GHOST_TabletData& GetCocoaTabletData()
+ { return m_tablet; }
+protected:
+ /**
+ * Tries to install a rendering context in this window.
+ * @param type The type of rendering context installed.
+ * @return Indication as to whether installation has succeeded.
+ */
+ virtual GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type);
+
+ /**
+ * Removes the current drawing context.
+ * @return Indication as to whether removal has succeeded.
+ */
+ virtual GHOST_TSuccess removeDrawingContext();
+
+ /**
+ * Invalidates the contents of this window.
+ * @return Indication of success.
+ */
+ virtual GHOST_TSuccess invalidate();
+
+ /**
+ * Sets the cursor visibility on the window using
+ * native window system calls.
+ */
+ virtual GHOST_TSuccess setWindowCursorVisibility(bool visible);
+
+ /**
+ * Sets the cursor warp accumulator. Overriden for workaround due to Cocoa next event after cursor set giving delta values non zero
+ */
+ inline virtual bool setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y);
+
+ /**
+ * Sets the cursor grab on the window using
+ * native window system calls.
+ * @param warp Only used when grab is enabled, hides the mouse and allows gragging outside the screen.
+ */
+ virtual GHOST_TSuccess setWindowCursorGrab(bool grab, bool warp, bool restore);
+
+ /**
+ * Sets the cursor shape on the window using
+ * native window system calls.
+ */
+ virtual GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape);
+
+ /**
+ * Sets the cursor shape on the window using
+ * native window system calls.
+ */
+ virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask,
+ int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color);
+
+ virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY);
+
+ /** The window containing the OpenGL view */
+ NSWindow *m_window;
+
+ /** The openGL view */
+ NSOpenGLView *m_openGLView;
+
+ /** The opgnGL drawing context */
+ NSOpenGLContext *m_openGLContext;
+
+ /** The mother SystemCocoa class to send events */
+ GHOST_SystemCocoa *m_systemCocoa;
+
+ /** The first created OpenGL context (for sharing display lists) */
+ static NSOpenGLContext *s_firstOpenGLcontext;
+
+ NSCursor* m_customCursor;
+
+ GHOST_TabletData m_tablet;
+
+ /**
+ * The width/height of the size rectangle in the lower right corner of a
+ * Mac/Carbon window. This is also the height of the gutter area.
+ */
+#ifdef GHOST_DRAW_CARBON_GUTTER
+ static const GHOST_TInt32 s_sizeRectSize;
+#endif // GHOST_DRAW_CARBON_GUTTER
+};
+
+#endif // _GHOST_WINDOW_COCOA_H_
+
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
new file mode 100644
index 00000000000..a2b146c1e33
--- /dev/null
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -0,0 +1,1028 @@
+/**
+ * $Id: GHOST_WindowCocoa.mm 23873 2009-10-15 20:09:50Z damien78 $
+ * ***** 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): Maarten Gribnau 05/2001
+ Damien Plisson 10/2009
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <Cocoa/Cocoa.h>
+
+#ifndef MAC_OS_X_VERSION_10_6
+//Use of the SetSystemUIMode function (64bit compatible)
+#include <Carbon/Carbon.h>
+#endif
+
+#include "GHOST_WindowCocoa.h"
+#include "GHOST_SystemCocoa.h"
+#include "GHOST_Debug.h"
+
+
+// Pixel Format Attributes for the windowed NSOpenGLContext
+static NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[] =
+{
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFAAccelerated,
+ //NSOpenGLPFAAllowOfflineRenderers, // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway
+ NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute) 32,
+ (NSOpenGLPixelFormatAttribute) 0
+};
+
+#pragma mark Cocoa window delegate object
+
+@interface CocoaWindowDelegate : NSObject
+{
+ GHOST_SystemCocoa *systemCocoa;
+ GHOST_WindowCocoa *associatedWindow;
+}
+
+- (void)setSystemAndWindowCocoa:(const GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa;
+- (void)windowWillClose:(NSNotification *)notification;
+- (void)windowDidBecomeKey:(NSNotification *)notification;
+- (void)windowDidResignKey:(NSNotification *)notification;
+- (void)windowDidUpdate:(NSNotification *)notification;
+- (void)windowDidResize:(NSNotification *)notification;
+@end
+
+@implementation CocoaWindowDelegate : NSObject
+- (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa
+{
+ systemCocoa = sysCocoa;
+ associatedWindow = winCocoa;
+}
+
+- (void)windowWillClose:(NSNotification *)notification
+{
+ systemCocoa->handleWindowEvent(GHOST_kEventWindowClose, associatedWindow);
+}
+
+- (void)windowDidBecomeKey:(NSNotification *)notification
+{
+ systemCocoa->handleWindowEvent(GHOST_kEventWindowActivate, associatedWindow);
+}
+
+- (void)windowDidResignKey:(NSNotification *)notification
+{
+ //The window is no more key when its own view becomes fullscreen
+ //but ghost doesn't know the view/window difference, so hide this fact
+ if (associatedWindow->getState() != GHOST_kWindowStateFullScreen)
+ systemCocoa->handleWindowEvent(GHOST_kEventWindowDeactivate, associatedWindow);
+}
+
+- (void)windowDidUpdate:(NSNotification *)notification
+{
+ systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, associatedWindow);
+}
+
+- (void)windowDidResize:(NSNotification *)notification
+{
+ systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, associatedWindow);
+}
+@end
+
+#pragma mark NSWindow subclass
+//We need to subclass it to tell that even borderless (fullscreen), it can become key (receive user events)
+@interface CocoaWindow: NSWindow
+{
+
+}
+-(BOOL)canBecomeKeyWindow;
+
+@end
+@implementation CocoaWindow
+
+-(BOOL)canBecomeKeyWindow
+{
+ return YES;
+}
+
+@end
+
+
+
+#pragma mark NSOpenGLView subclass
+//We need to subclass it in order to give Cocoa the feeling key events are trapped
+@interface CocoaOpenGLView : NSOpenGLView
+{
+
+}
+@end
+@implementation CocoaOpenGLView
+
+- (BOOL)acceptsFirstResponder
+{
+ return YES;
+}
+
+//The trick to prevent Cocoa from complaining (beeping)
+- (void)keyDown:(NSEvent *)theEvent
+{}
+
+- (BOOL)isOpaque
+{
+ return YES;
+}
+
+@end
+
+
+#pragma mark initialization / finalization
+
+NSOpenGLContext* GHOST_WindowCocoa::s_firstOpenGLcontext = nil;
+
+GHOST_WindowCocoa::GHOST_WindowCocoa(
+ GHOST_SystemCocoa *systemCocoa,
+ const STR_String& title,
+ GHOST_TInt32 left,
+ GHOST_TInt32 top,
+ GHOST_TUns32 width,
+ GHOST_TUns32 height,
+ GHOST_TWindowState state,
+ GHOST_TDrawingContextType type,
+ const bool stereoVisual
+) :
+ GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone),
+ m_customCursor(0)
+{
+ m_systemCocoa = systemCocoa;
+ m_fullScreen = false;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+
+ //Creates the window
+ NSRect rect;
+
+ rect.origin.x = left;
+ rect.origin.y = top;
+ rect.size.width = width;
+ rect.size.height = height;
+
+ m_window = [[CocoaWindow alloc] initWithContentRect:rect
+ styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask
+ backing:NSBackingStoreBuffered defer:NO];
+ if (m_window == nil) {
+ [pool drain];
+ return;
+ }
+
+ setTitle(title);
+
+
+ //Creates the OpenGL View inside the window
+ NSOpenGLPixelFormat *pixelFormat =
+ [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow];
+
+ m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect
+ pixelFormat:pixelFormat];
+
+ [pixelFormat release];
+
+ m_openGLContext = [m_openGLView openGLContext]; //This context will be replaced by the proper one just after
+
+ [m_window setContentView:m_openGLView];
+ [m_window setInitialFirstResponder:m_openGLView];
+
+ [m_window setReleasedWhenClosed:NO]; //To avoid bad pointer exception in case of user closing the window
+
+ [m_window makeKeyAndOrderFront:nil];
+
+ setDrawingContextType(type);
+ updateDrawingContext();
+ activateDrawingContext();
+
+ m_tablet.Active = GHOST_kTabletModeNone;
+
+ CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init];
+ [windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
+ [m_window setDelegate:windowDelegate];
+
+ [m_window setAcceptsMouseMovedEvents:YES];
+
+ if (state == GHOST_kWindowStateFullScreen)
+ setState(GHOST_kWindowStateFullScreen);
+
+ [pool drain];
+}
+
+
+GHOST_WindowCocoa::~GHOST_WindowCocoa()
+{
+ if (m_customCursor) delete m_customCursor;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [m_openGLView release];
+
+ if (m_window) {
+ [m_window close];
+ [[m_window delegate] release];
+ [m_window release];
+ m_window = nil;
+ }
+
+ //Check for other blender opened windows and make the frontmost key
+ NSArray *windowsList = [NSApp orderedWindows];
+ if ([windowsList count]) {
+ [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
+ }
+ [pool drain];
+}
+
+#pragma mark accessors
+
+bool GHOST_WindowCocoa::getValid() const
+{
+ bool valid;
+ if (!m_fullScreen) {
+ valid = (m_window != 0); //&& ::IsValidWindowPtr(m_windowRef);
+ }
+ else {
+ valid = true;
+ }
+ return valid;
+}
+
+
+void GHOST_WindowCocoa::setTitle(const STR_String& title)
+{
+ GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setTitle(): window invalid")
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSString *windowTitle = [[NSString alloc] initWithUTF8String:title];
+
+ //Set associated file if applicable
+ if ([windowTitle hasPrefix:@"Blender"])
+ {
+ NSRange fileStrRange;
+ NSString *associatedFileName;
+ int len;
+
+ fileStrRange.location = [windowTitle rangeOfString:@"["].location+1;
+ len = [windowTitle rangeOfString:@"]"].location - fileStrRange.location;
+
+ if (len >0)
+ {
+ fileStrRange.length = len;
+ associatedFileName = [windowTitle substringWithRange:fileStrRange];
+ @try {
+ [m_window setRepresentedFilename:associatedFileName];
+ }
+ @catch (NSException * e) {
+ printf("\nInvalid file path given in window title");
+ }
+ [m_window setTitle:[associatedFileName lastPathComponent]];
+ }
+ else {
+ [m_window setTitle:windowTitle];
+ [m_window setRepresentedFilename:@""];
+ }
+
+ } else {
+ [m_window setTitle:windowTitle];
+ [m_window setRepresentedFilename:@""];
+ }
+
+
+ [windowTitle release];
+ [pool drain];
+}
+
+
+void GHOST_WindowCocoa::getTitle(STR_String& title) const
+{
+ GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getTitle(): window invalid")
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSString *windowTitle = [m_window title];
+
+ if (windowTitle != nil) {
+ title = [windowTitle UTF8String];
+ }
+
+ [pool drain];
+}
+
+
+void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect& bounds) const
+{
+ NSRect rect;
+ GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getWindowBounds(): window invalid")
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSRect screenSize = [[m_window screen] visibleFrame];
+
+ rect = [m_window frame];
+
+ bounds.m_b = screenSize.size.height - (rect.origin.y -screenSize.origin.y);
+ bounds.m_l = rect.origin.x -screenSize.origin.x;
+ bounds.m_r = rect.origin.x-screenSize.origin.x + rect.size.width;
+ bounds.m_t = screenSize.size.height - (rect.origin.y + rect.size.height -screenSize.origin.y);
+
+ [pool drain];
+}
+
+
+void GHOST_WindowCocoa::getClientBounds(GHOST_Rect& bounds) const
+{
+ NSRect rect;
+ GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getClientBounds(): window invalid")
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ if (!m_fullScreen)
+ {
+ NSRect screenSize = [[m_window screen] visibleFrame];
+
+ //Max window contents as screen size (excluding title bar...)
+ NSRect contentRect = [CocoaWindow contentRectForFrameRect:screenSize
+ styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)];
+
+ rect = [m_window contentRectForFrameRect:[m_window frame]];
+
+ bounds.m_b = contentRect.size.height - (rect.origin.y -contentRect.origin.y);
+ bounds.m_l = rect.origin.x -contentRect.origin.x;
+ bounds.m_r = rect.origin.x-contentRect.origin.x + rect.size.width;
+ bounds.m_t = contentRect.size.height - (rect.origin.y + rect.size.height -contentRect.origin.y);
+ }
+ else {
+ NSRect screenSize = [[m_window screen] frame];
+
+ bounds.m_b = screenSize.origin.y + screenSize.size.height;
+ bounds.m_l = screenSize.origin.x;
+ bounds.m_r = screenSize.origin.x + screenSize.size.width;
+ bounds.m_t = screenSize.origin.y;
+ }
+ [pool drain];
+}
+
+
+GHOST_TSuccess GHOST_WindowCocoa::setClientWidth(GHOST_TUns32 width)
+{
+ GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientWidth(): window invalid")
+ GHOST_Rect cBnds, wBnds;
+ getClientBounds(cBnds);
+ if (((GHOST_TUns32)cBnds.getWidth()) != width) {
+ NSSize size;
+ size.width=width;
+ size.height=cBnds.getHeight();
+ [m_window setContentSize:size];
+ }
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_WindowCocoa::setClientHeight(GHOST_TUns32 height)
+{
+ GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientHeight(): window invalid")
+ GHOST_Rect cBnds, wBnds;
+ getClientBounds(cBnds);
+ if (((GHOST_TUns32)cBnds.getHeight()) != height) {
+ NSSize size;
+ size.width=cBnds.getWidth();
+ size.height=height;
+ [m_window setContentSize:size];
+ }
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_WindowCocoa::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
+{
+ GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientSize(): window invalid")
+ GHOST_Rect cBnds, wBnds;
+ getClientBounds(cBnds);
+ if ((((GHOST_TUns32)cBnds.getWidth()) != width) ||
+ (((GHOST_TUns32)cBnds.getHeight()) != height)) {
+ NSSize size;
+ size.width=width;
+ size.height=height;
+ [m_window setContentSize:size];
+ }
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TWindowState GHOST_WindowCocoa::getState() const
+{
+ GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getState(): window invalid")
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ GHOST_TWindowState state;
+ if (m_fullScreen) {
+ state = GHOST_kWindowStateFullScreen;
+ }
+ else if ([m_window isMiniaturized]) {
+ state = GHOST_kWindowStateMinimized;
+ }
+ else if ([m_window isZoomed]) {
+ state = GHOST_kWindowStateMaximized;
+ }
+ else {
+ state = GHOST_kWindowStateNormal;
+ }
+ [pool drain];
+ return state;
+}
+
+
+void GHOST_WindowCocoa::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
+{
+ GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::screenToClient(): window invalid")
+
+ NSPoint screenCoord;
+ NSPoint baseCoord;
+
+ screenCoord.x = inX;
+ screenCoord.y = inY;
+
+ baseCoord = [m_window convertScreenToBase:screenCoord];
+
+ outX = baseCoord.x;
+ outY = baseCoord.y;
+}
+
+
+void GHOST_WindowCocoa::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
+{
+ GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::clientToScreen(): window invalid")
+
+ NSPoint screenCoord;
+ NSPoint baseCoord;
+
+ baseCoord.x = inX;
+ baseCoord.y = inY;
+
+ screenCoord = [m_window convertBaseToScreen:baseCoord];
+
+ outX = screenCoord.x;
+ outY = screenCoord.y;
+}
+
+/**
+ * @note Fullscreen switch is not actual fullscreen with display capture. As this capture removes all OS X window manager features.
+ * Instead, the menu bar and the dock are hidden, and the window is made borderless and enlarged.
+ * Thus, process switch, exposé, spaces, ... still work in fullscreen mode
+ */
+GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
+{
+ GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setState(): window invalid")
+ switch (state) {
+ case GHOST_kWindowStateMinimized:
+ [m_window miniaturize:nil];
+ break;
+ case GHOST_kWindowStateMaximized:
+ [m_window zoom:nil];
+ break;
+
+ case GHOST_kWindowStateFullScreen:
+ if (!m_fullScreen)
+ {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ //This status change needs to be done before Cocoa call to enter fullscreen mode
+ //to give window delegate hint not to forward its deactivation to ghost wm that doesn't know view/window difference
+ m_fullScreen = true;
+
+#ifdef MAC_OS_X_VERSION_10_6
+ //10.6 provides Cocoa functions to autoshow menu bar, and to change a window style
+ //Hide menu & dock if needed
+ if ([[m_window screen] isEqual:[NSScreen mainScreen]])
+ {
+ [NSApp setPresentationOptions:(NSApplicationPresentationHideDock | NSApplicationPresentationAutoHideMenuBar)];
+ }
+ //Make window borderless and enlarge it
+ [m_window setStyleMask:NSBorderlessWindowMask];
+ [m_window setFrame:[[m_window screen] frame] display:YES];
+#else
+ //With 10.5, we need to create a new window to change its style to borderless
+ //Hide menu & dock if needed
+ if ([[m_window screen] isEqual:[NSScreen mainScreen]])
+ {
+ //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:NO];
+ //One of the very few 64bit compatible Carbon function
+ SetSystemUIMode(kUIModeAllHidden,kUIOptionAutoShowMenuBar);
+ }
+ //Create a fullscreen borderless window
+ CocoaWindow *tmpWindow = [[CocoaWindow alloc]
+ initWithContentRect:[[m_window screen] frame]
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:YES];
+ //Copy current window parameters
+ [tmpWindow setTitle:[m_window title]];
+ [tmpWindow setRepresentedFilename:[m_window representedFilename]];
+ [tmpWindow setReleasedWhenClosed:NO];
+ [tmpWindow setAcceptsMouseMovedEvents:YES];
+ [tmpWindow setDelegate:[m_window delegate]];
+
+ //Assign the openGL view to the new window
+ [tmpWindow setContentView:m_openGLView];
+
+ //Show the new window
+ [tmpWindow makeKeyAndOrderFront:nil];
+ //Close and release old window
+ [m_window setDelegate:nil]; // To avoid the notification of "window closed" event
+ [m_window close];
+ [m_window release];
+ m_window = tmpWindow;
+#endif
+
+ //Tell WM of view new size
+ m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this);
+
+ [pool drain];
+ }
+ break;
+ case GHOST_kWindowStateNormal:
+ default:
+ if (m_fullScreen)
+ {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ m_fullScreen = false;
+
+ //Exit fullscreen
+#ifdef MAC_OS_X_VERSION_10_6
+ //Show again menu & dock if needed
+ if ([[m_window screen] isEqual:[NSScreen mainScreen]])
+ {
+ [NSApp setPresentationOptions:NSApplicationPresentationDefault];
+ }
+ //Make window normal and resize it
+ [m_window setStyleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)];
+ [m_window setFrame:[[m_window screen] visibleFrame] display:YES];
+#else
+ //With 10.5, we need to create a new window to change its style to borderless
+ //Show menu & dock if needed
+ if ([[m_window screen] isEqual:[NSScreen mainScreen]])
+ {
+ //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:YES];
+ SetSystemUIMode(kUIModeNormal, 0); //One of the very few 64bit compatible Carbon function
+ }
+ //Create a fullscreen borderless window
+ CocoaWindow *tmpWindow = [[CocoaWindow alloc]
+ initWithContentRect:[[m_window screen] frame]
+ styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)
+ backing:NSBackingStoreBuffered
+ defer:YES];
+ //Copy current window parameters
+ [tmpWindow setTitle:[m_window title]];
+ [tmpWindow setRepresentedFilename:[m_window representedFilename]];
+ [tmpWindow setReleasedWhenClosed:NO];
+ [tmpWindow setAcceptsMouseMovedEvents:YES];
+ [tmpWindow setDelegate:[m_window delegate]];
+
+ //Assign the openGL view to the new window
+ [tmpWindow setContentView:m_openGLView];
+
+ //Show the new window
+ [tmpWindow makeKeyAndOrderFront:nil];
+ //Close and release old window
+ [m_window setDelegate:nil]; // To avoid the notification of "window closed" event
+ [m_window close];
+ [m_window release];
+ m_window = tmpWindow;
+#endif
+
+ //Tell WM of view new size
+ m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this);
+
+ [pool drain];
+ }
+ else if ([m_window isMiniaturized])
+ [m_window deminiaturize:nil];
+ else if ([m_window isZoomed])
+ [m_window zoom:nil];
+ break;
+ }
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_WindowCocoa::setModifiedState(bool isUnsavedChanges)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ [m_window setDocumentEdited:isUnsavedChanges];
+
+ [pool drain];
+ return GHOST_Window::setModifiedState(isUnsavedChanges);
+}
+
+
+
+GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order)
+{
+ GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setOrder(): window invalid")
+ if (order == GHOST_kWindowOrderTop) {
+ [m_window orderFront:nil];
+ }
+ else {
+ [m_window orderBack:nil];
+ }
+ return GHOST_kSuccess;
+}
+
+#pragma mark Drawing context
+
+/*#define WAIT_FOR_VSYNC 1*/
+
+GHOST_TSuccess GHOST_WindowCocoa::swapBuffers()
+{
+ if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
+ if (m_openGLContext != nil) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [m_openGLContext flushBuffer];
+ [pool drain];
+ return GHOST_kSuccess;
+ }
+ }
+ return GHOST_kFailure;
+}
+
+GHOST_TSuccess GHOST_WindowCocoa::updateDrawingContext()
+{
+ if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
+ if (m_openGLContext != nil) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [m_openGLContext update];
+ [pool drain];
+ return GHOST_kSuccess;
+ }
+ }
+ return GHOST_kFailure;
+}
+
+GHOST_TSuccess GHOST_WindowCocoa::activateDrawingContext()
+{
+ if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
+ if (m_openGLContext != nil) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [m_openGLContext makeCurrentContext];
+ [pool drain];
+ return GHOST_kSuccess;
+ }
+ }
+ return GHOST_kFailure;
+}
+
+
+GHOST_TSuccess GHOST_WindowCocoa::installDrawingContext(GHOST_TDrawingContextType type)
+{
+ GHOST_TSuccess success = GHOST_kFailure;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSOpenGLPixelFormat *pixelFormat;
+ NSOpenGLContext *tmpOpenGLContext;
+
+ switch (type) {
+ case GHOST_kDrawingContextTypeOpenGL:
+ if (!getValid()) break;
+
+ pixelFormat = [m_openGLView pixelFormat];
+ tmpOpenGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
+ shareContext:s_firstOpenGLcontext];
+ if (tmpOpenGLContext == nil) {
+ success = GHOST_kFailure;
+ break;
+ }
+
+ if (!s_firstOpenGLcontext) s_firstOpenGLcontext = tmpOpenGLContext;
+#ifdef WAIT_FOR_VSYNC
+ /* wait for vsync, to avoid tearing artifacts */
+ [tmpOpenGLContext setValues:1 forParameter:NSOpenGLCPSwapInterval];
+#endif
+ [m_openGLView setOpenGLContext:tmpOpenGLContext];
+ [tmpOpenGLContext setView:m_openGLView];
+
+ m_openGLContext = tmpOpenGLContext;
+ break;
+
+ case GHOST_kDrawingContextTypeNone:
+ success = GHOST_kSuccess;
+ break;
+
+ default:
+ break;
+ }
+ [pool drain];
+ return success;
+}
+
+
+GHOST_TSuccess GHOST_WindowCocoa::removeDrawingContext()
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ switch (m_drawingContextType) {
+ case GHOST_kDrawingContextTypeOpenGL:
+ if (m_openGLContext)
+ {
+ [m_openGLView clearGLContext];
+ if (s_firstOpenGLcontext == m_openGLContext) s_firstOpenGLcontext = nil;
+ m_openGLContext = nil;
+ }
+ [pool drain];
+ return GHOST_kSuccess;
+ case GHOST_kDrawingContextTypeNone:
+ [pool drain];
+ return GHOST_kSuccess;
+ break;
+ default:
+ [pool drain];
+ return GHOST_kFailure;
+ }
+}
+
+
+GHOST_TSuccess GHOST_WindowCocoa::invalidate()
+{
+ GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::invalidate(): window invalid")
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [m_openGLView setNeedsDisplay:YES];
+ [pool drain];
+ return GHOST_kSuccess;
+}
+
+#pragma mark Cursor handling
+
+void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
+{
+ static bool systemCursorVisible = true;
+
+ NSAutoreleasePool *pool =[[NSAutoreleasePool alloc] init];
+
+ NSCursor *tmpCursor =nil;
+
+ if (visible != systemCursorVisible) {
+ if (visible) {
+ [NSCursor unhide];
+ systemCursorVisible = true;
+ }
+ else {
+ [NSCursor hide];
+ systemCursorVisible = false;
+ }
+ }
+
+ if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
+ tmpCursor = m_customCursor;
+ } else {
+ switch (cursor) {
+ case GHOST_kStandardCursorDestroy:
+ tmpCursor = [NSCursor disappearingItemCursor];
+ break;
+ case GHOST_kStandardCursorText:
+ tmpCursor = [NSCursor IBeamCursor];
+ break;
+ case GHOST_kStandardCursorCrosshair:
+ tmpCursor = [NSCursor crosshairCursor];
+ break;
+ case GHOST_kStandardCursorUpDown:
+ tmpCursor = [NSCursor resizeUpDownCursor];
+ break;
+ case GHOST_kStandardCursorLeftRight:
+ tmpCursor = [NSCursor resizeLeftRightCursor];
+ break;
+ case GHOST_kStandardCursorTopSide:
+ tmpCursor = [NSCursor resizeUpCursor];
+ break;
+ case GHOST_kStandardCursorBottomSide:
+ tmpCursor = [NSCursor resizeDownCursor];
+ break;
+ case GHOST_kStandardCursorLeftSide:
+ tmpCursor = [NSCursor resizeLeftCursor];
+ break;
+ case GHOST_kStandardCursorRightSide:
+ tmpCursor = [NSCursor resizeRightCursor];
+ break;
+ case GHOST_kStandardCursorRightArrow:
+ case GHOST_kStandardCursorInfo:
+ case GHOST_kStandardCursorLeftArrow:
+ case GHOST_kStandardCursorHelp:
+ case GHOST_kStandardCursorCycle:
+ case GHOST_kStandardCursorSpray:
+ case GHOST_kStandardCursorWait:
+ case GHOST_kStandardCursorTopLeftCorner:
+ case GHOST_kStandardCursorTopRightCorner:
+ case GHOST_kStandardCursorBottomRightCorner:
+ case GHOST_kStandardCursorBottomLeftCorner:
+ case GHOST_kStandardCursorDefault:
+ default:
+ tmpCursor = [NSCursor arrowCursor];
+ break;
+ };
+ }
+ [tmpCursor set];
+ [pool drain];
+}
+
+
+
+GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible)
+{
+ if ([m_window isVisible]) {
+ loadCursor(visible, getCursorShape());
+ }
+
+ return GHOST_kSuccess;
+}
+
+
+//Override this method to provide set feature even if not in warp
+inline bool GHOST_WindowCocoa::setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y)
+{
+ m_cursorWarpAccumPos[0]= x;
+ m_cursorWarpAccumPos[1]= y;
+
+ return GHOST_kSuccess;
+}
+
+
+GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(bool grab, bool warp, bool restore)
+{
+ if (grab)
+ {
+ //No need to perform grab without warp as it is always on in OS X
+ if(warp) {
+ GHOST_TInt32 x_old,y_old;
+
+ m_cursorWarp= true;
+ m_systemCocoa->getCursorPosition(x_old,y_old);
+ screenToClient(x_old, y_old, m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]);
+ //Warp position is stored in client (window base) coordinates
+ setWindowCursorVisibility(false);
+ return CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure;
+ }
+ }
+ else {
+ if(m_cursorWarp)
+ {/* are we exiting warp */
+ setWindowCursorVisibility(true);
+ /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */
+ if(restore) {
+ GHOST_Rect bounds;
+ GHOST_TInt32 x_new, y_new, x_cur, y_cur;
+
+ getClientBounds(bounds);
+ x_new= m_cursorWarpInitPos[0]+m_cursorWarpAccumPos[0];
+ y_new= m_cursorWarpInitPos[1]+m_cursorWarpAccumPos[1];
+
+ if(x_new < 0) x_new = 0;
+ if(y_new < 0) y_new = 0;
+ if(x_new > bounds.getWidth()) x_new = bounds.getWidth();
+ if(y_new > bounds.getHeight()) y_new = bounds.getHeight();
+
+ //get/set cursor position works in screen coordinates
+ clientToScreen(x_new, y_new, x_cur, y_cur);
+ m_systemCocoa->setCursorPosition(x_cur, y_cur);
+
+ //As Cocoa will give as first deltaX,deltaY this change in cursor position, we need to compensate for it
+ //Issue appearing in case of two transform operations conducted w/o mouse motion in between
+ x_new=m_cursorWarpAccumPos[0];
+ y_new=m_cursorWarpAccumPos[1];
+ setCursorWarpAccum(-x_new, -y_new);
+ }
+ else {
+ GHOST_TInt32 x_new, y_new;
+ //get/set cursor position works in screen coordinates
+ clientToScreen(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1], x_new, y_new);
+ m_systemCocoa->setCursorPosition(x_new, y_new);
+ setCursorWarpAccum(0, 0);
+ }
+
+ m_cursorWarp= false;
+ return CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure;
+ }
+ }
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape)
+{
+ if (m_customCursor) {
+ [m_customCursor release];
+ m_customCursor = nil;
+ }
+
+ if ([m_window isVisible]) {
+ loadCursor(getCursorVisibility(), shape);
+ }
+
+ return GHOST_kSuccess;
+}
+
+/** Reverse the bits in a GHOST_TUns8
+static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
+{
+ ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA);
+ ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC);
+ ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0);
+ return ch;
+}
+*/
+
+
+/** Reverse the bits in a GHOST_TUns16 */
+static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
+{
+ shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA);
+ shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC);
+ shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0);
+ shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00);
+ return shrt;
+}
+
+GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask,
+ int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color)
+{
+ int y,nbUns16;
+ NSPoint hotSpotPoint;
+ NSBitmapImageRep *cursorImageRep;
+ NSImage *cursorImage;
+ NSSize imSize;
+ GHOST_TUns16 *cursorBitmap;
+
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ if (m_customCursor) {
+ [m_customCursor release];
+ m_customCursor = nil;
+ }
+
+
+ cursorImageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil
+ pixelsWide:sizex
+ pixelsHigh:sizey
+ bitsPerSample:1
+ samplesPerPixel:2
+ hasAlpha:YES
+ isPlanar:YES
+ colorSpaceName:NSDeviceBlackColorSpace
+ bytesPerRow:(sizex/8 + (sizex%8 >0 ?1:0))
+ bitsPerPixel:1];
+
+
+ cursorBitmap = (GHOST_TUns16*)[cursorImageRep bitmapData];
+ nbUns16 = [cursorImageRep bytesPerPlane]/2;
+
+ for (y=0; y<nbUns16; y++) {
+#if !defined(__LITTLE_ENDIAN__)
+ cursorBitmap[y] = uns16ReverseBits((bitmap[2*y]<<0) | (bitmap[2*y+1]<<8));
+ cursorBitmap[nbUns16+y] = uns16ReverseBits((mask[2*y]<<0) | (mask[2*y+1]<<8));
+#else
+ cursorBitmap[y] = uns16ReverseBits((bitmap[2*y+1]<<0) | (bitmap[2*y]<<8));
+ cursorBitmap[nbUns16+y] = uns16ReverseBits((mask[2*y+1]<<0) | (mask[2*y]<<8));
+#endif
+
+ }
+
+
+ imSize.width = sizex;
+ imSize.height= sizey;
+ cursorImage = [[NSImage alloc] initWithSize:imSize];
+ [cursorImage addRepresentation:cursorImageRep];
+
+ hotSpotPoint.x = hotX;
+ hotSpotPoint.y = hotY;
+
+ //foreground and background color parameter is not handled for now (10.6)
+ m_customCursor = [[NSCursor alloc] initWithImage:cursorImage
+ hotSpot:hotSpotPoint];
+
+ [cursorImageRep release];
+ [cursorImage release];
+
+ if ([m_window isVisible]) {
+ loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
+ }
+ [pool drain];
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2],
+ GHOST_TUns8 mask[16][2], int hotX, int hotY)
+{
+ return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*) mask, 16, 16, hotX, hotY, 0, 1);
+}
diff --git a/source/blender/editors/mesh/bmesh_tools.c b/source/blender/editors/mesh/bmesh_tools.c
index 9b31a06edb3..ad1654d2f3a 100644
--- a/source/blender/editors/mesh/bmesh_tools.c
+++ b/source/blender/editors/mesh/bmesh_tools.c
@@ -2990,9 +2990,10 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
then rip the two adjacent edges in the vert fan.*/
if (em->bm->totvertsel == 1 && em->bm->totedgesel == 0 && em->bm->totfacesel == 0) {
/*find selected vert*/
- BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL)
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
if (BM_TestHFlag(v, BM_SELECT))
break;
+ }
/*this should be impossible, but sanity checks are a good thing*/
if (!v)
diff --git a/source/blender/gpu/gpu_buffers.h b/source/blender/gpu/gpu_buffers.h
new file mode 100644
index 00000000000..7377046ee63
--- /dev/null
+++ b/source/blender/gpu/gpu_buffers.h
@@ -0,0 +1,157 @@
+/**
+ * $Id: gpu_buffers.h 23816 2009-10-13 19:02:30Z nicholasbishop $
+ *
+ * ***** 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __GPU_BUFFERS_H__
+#define __GPU_BUFFERS_H__
+
+#define MAX_FREE_GPU_BUFFERS 8
+
+#ifdef _DEBUG
+/*#define DEBUG_VBO(X) printf(X)*/
+#define DEBUG_VBO(X)
+#else
+#define DEBUG_VBO(X)
+#endif
+
+struct DerivedMesh;
+
+/* V - vertex, N - normal, T - uv, C - color
+ F - float, UB - unsigned byte */
+#define GPU_BUFFER_INTER_V3F 1
+#define GPU_BUFFER_INTER_N3F 2
+#define GPU_BUFFER_INTER_T2F 3
+#define GPU_BUFFER_INTER_C3UB 4
+#define GPU_BUFFER_INTER_C4UB 5
+#define GPU_BUFFER_INTER_END -1
+
+typedef struct GPUBuffer
+{
+ int size; /* in bytes */
+ void *pointer; /* used with vertex arrays */
+ unsigned int id; /* used with vertex buffer objects */
+} GPUBuffer;
+
+typedef struct GPUBufferPool
+{
+ int size; /* number of allocated buffers stored */
+ int start; /* for a queue like structure */
+ /* when running out of space for storing buffers,
+ the last one used will be thrown away */
+
+ GPUBuffer* buffers[MAX_FREE_GPU_BUFFERS];
+} GPUBufferPool;
+
+typedef struct GPUBufferMaterial
+{
+ int start; /* at which vertex in the buffer the material starts */
+ int end; /* at which vertex it ends */
+ char mat_nr;
+} GPUBufferMaterial;
+
+typedef struct IndexLink {
+ int element;
+ struct IndexLink *next;
+} IndexLink;
+
+typedef struct GPUDrawObject
+{
+ GPUBuffer *vertices;
+ GPUBuffer *normals;
+ GPUBuffer *uv;
+ GPUBuffer *colors;
+ GPUBuffer *edges;
+ GPUBuffer *uvedges;
+
+ int *faceRemap; /* at what index was the face originally in DerivedMesh */
+ IndexLink *indices; /* given an index, find all elements using it */
+ IndexLink *indexMem; /* for faster memory allocation/freeing */
+ int indexMemUsage; /* how many are already allocated */
+ int colType;
+
+ GPUBufferMaterial *materials;
+
+ int nmaterials;
+ int nelements; /* (number of faces) * 3 */
+ int nlooseverts;
+ int nedges;
+ int nindices;
+ int legacy; /* if there was a failure allocating some buffer, use old rendering code */
+
+} GPUDrawObject;
+
+typedef struct GPUAttrib
+{
+ int index;
+ int size;
+ int type;
+} GPUAttrib;
+
+GPUBufferPool *GPU_buffer_pool_new();
+void GPU_buffer_pool_free( GPUBufferPool *pool ); /* TODO: Find a place where to call this function on exit */
+
+GPUBuffer *GPU_buffer_alloc( int size, GPUBufferPool *pool );
+void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool );
+
+GPUDrawObject *GPU_drawobject_new( struct DerivedMesh *dm );
+void GPU_drawobject_free( struct DerivedMesh *dm );
+
+/* called before drawing */
+void GPU_vertex_setup( struct DerivedMesh *dm );
+void GPU_normal_setup( struct DerivedMesh *dm );
+void GPU_uv_setup( struct DerivedMesh *dm );
+void GPU_color_setup( struct DerivedMesh *dm );
+void GPU_edge_setup( struct DerivedMesh *dm ); /* does not mix with other data */
+void GPU_uvedge_setup( struct DerivedMesh *dm );
+void GPU_interleaved_setup( GPUBuffer *buffer, int data[] );
+int GPU_attrib_element_size( GPUAttrib data[], int numdata );
+void GPU_interleaved_attrib_setup( GPUBuffer *buffer, GPUAttrib data[], int numdata );
+
+/* can't lock more than one buffer at once */
+void *GPU_buffer_lock( GPUBuffer *buffer );
+void *GPU_buffer_lock_stream( GPUBuffer *buffer );
+void GPU_buffer_unlock( GPUBuffer *buffer );
+
+/* upload three unsigned chars, representing RGB colors, for each vertex. Resets dm->drawObject->colType to -1 */
+void GPU_color3_upload( struct DerivedMesh *dm, unsigned char *data );
+/* upload four unsigned chars, representing RGBA colors, for each vertex. Resets dm->drawObject->colType to -1 */
+void GPU_color4_upload( struct DerivedMesh *dm, unsigned char *data );
+/* switch color rendering on=1/off=0 */
+void GPU_color_switch( int mode );
+
+void GPU_buffer_draw_elements( GPUBuffer *elements, unsigned int mode, int start, int count );
+
+/* called after drawing */
+void GPU_buffer_unbind();
+
+int GPU_buffer_legacy( struct DerivedMesh *dm );
+
+#endif
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
new file mode 100644
index 00000000000..6b465b64590
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -0,0 +1,1262 @@
+/**
+ * $Id: gpu_buffers.c 23816 2009-10-13 19:02:30Z nicholasbishop $
+ *
+ * ***** 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. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * 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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+
+#include "GL/glew.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+
+#include "DNA_meshdata_types.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_utildefines.h"
+
+#include "DNA_userdef_types.h"
+
+#include "gpu_buffers.h"
+
+#define GPU_BUFFER_VERTEX_STATE 1
+#define GPU_BUFFER_NORMAL_STATE 2
+#define GPU_BUFFER_TEXCOORD_STATE 4
+#define GPU_BUFFER_COLOR_STATE 8
+#define GPU_BUFFER_ELEMENT_STATE 16
+
+#define MAX_GPU_ATTRIB_DATA 32
+
+/* -1 - undefined, 0 - vertex arrays, 1 - VBOs */
+int useVBOs = -1;
+GPUBufferPool *globalPool = 0;
+int GLStates = 0;
+GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
+
+GPUBufferPool *GPU_buffer_pool_new()
+{
+ GPUBufferPool *pool;
+
+ DEBUG_VBO("GPU_buffer_pool_new\n");
+
+ if( useVBOs < 0 ) {
+ if( GL_ARB_vertex_buffer_object ) {
+ DEBUG_VBO( "Vertex Buffer Objects supported.\n" );
+ useVBOs = 1;
+ }
+ else {
+ DEBUG_VBO( "Vertex Buffer Objects NOT supported.\n" );
+ useVBOs = 0;
+ }
+ }
+
+ pool = MEM_callocN(sizeof(GPUBufferPool), "GPU_buffer_pool_new");
+
+ return pool;
+}
+
+void GPU_buffer_pool_free(GPUBufferPool *pool)
+{
+ int i;
+
+ DEBUG_VBO("GPU_buffer_pool_free\n");
+
+ if( pool == 0 )
+ pool = globalPool;
+ if( pool == 0 )
+ return;
+
+ while( pool->start < 0 )
+ pool->start += MAX_FREE_GPU_BUFFERS;
+
+ for( i = 0; i < pool->size; i++ ) {
+ if( useVBOs ) {
+ glDeleteBuffersARB( 1, &pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS]->id );
+ }
+ else {
+ MEM_freeN( pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS]->pointer );
+ }
+ MEM_freeN(pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS]);
+ }
+ MEM_freeN(pool);
+}
+
+void GPU_buffer_pool_remove( int index, GPUBufferPool *pool )
+{
+ int i;
+
+ DEBUG_VBO("GPU_buffer_pool_remove\n");
+
+ while( pool->start < 0 )
+ pool->start += MAX_FREE_GPU_BUFFERS;
+ for( i = index; i < pool->size-1; i++ ) {
+ pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS] = pool->buffers[(pool->start+i+1)%MAX_FREE_GPU_BUFFERS];
+ }
+ pool->size--;
+}
+
+void GPU_buffer_pool_delete_last( GPUBufferPool *pool )
+{
+ int last;
+
+ DEBUG_VBO("GPU_buffer_pool_delete_last\n");
+
+ if( pool->size == 0 )
+ return;
+
+ last = pool->start+pool->size-1;
+ while( last < 0 )
+ last += MAX_FREE_GPU_BUFFERS;
+ last = (last+MAX_FREE_GPU_BUFFERS)%MAX_FREE_GPU_BUFFERS;
+
+ if( useVBOs ) {
+ glDeleteBuffersARB(1,&pool->buffers[last]->id);
+ MEM_freeN( pool->buffers[last] );
+ }
+ else {
+ MEM_freeN( pool->buffers[last]->pointer );
+ MEM_freeN( pool->buffers[last] );
+ }
+ pool->size--;
+}
+
+GPUBuffer *GPU_buffer_alloc( int size, GPUBufferPool *pool )
+{
+ char buffer[60];
+ int i;
+ int cursize;
+ GPUBuffer *allocated;
+ int bestfit = -1;
+
+ DEBUG_VBO("GPU_buffer_alloc\n");
+
+ if( pool == 0 ) {
+ if( globalPool == 0 )
+ globalPool = GPU_buffer_pool_new();
+ pool = globalPool;
+ }
+
+ while( pool->start < 0 )
+ pool->start += MAX_FREE_GPU_BUFFERS;
+
+ for( i = 0; i < pool->size; i++ ) {
+ int actuali = (pool->start+i)%MAX_FREE_GPU_BUFFERS;
+ cursize = pool->buffers[actuali]->size;
+ if( cursize == size ) {
+ allocated = pool->buffers[actuali];
+ GPU_buffer_pool_remove(i,pool);
+ DEBUG_VBO("free buffer of exact size found\n");
+ return allocated;
+ }
+ /* smaller buffers won't fit data and buffers at least twice as big are a waste of memory */
+ else if( cursize > size && size > cursize/2 ) {
+ /* is it closer to the required size than the last appropriate buffer found. try to save memory */
+ if( bestfit == -1 || pool->buffers[(pool->start+bestfit)%MAX_FREE_GPU_BUFFERS]->size > cursize ) {
+ bestfit = i;
+ }
+ }
+ }
+ if( bestfit == -1 ) {
+ DEBUG_VBO("allocating a new buffer\n");
+
+ allocated = MEM_mallocN(sizeof(GPUBuffer), "GPU_buffer_alloc");
+ allocated->size = size;
+ if( useVBOs == 1 ) {
+ glGenBuffersARB( 1, &allocated->id );
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, allocated->id );
+ glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, 0, GL_STATIC_DRAW_ARB );
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
+ }
+ else {
+ allocated->pointer = MEM_mallocN(size, "GPU_buffer_alloc_vertexarray");
+ while( allocated->pointer == 0 && pool->size > 0 ) {
+ GPU_buffer_pool_delete_last(pool);
+ allocated->pointer = MEM_mallocN(size, "GPU_buffer_alloc_vertexarray");
+ }
+ if( allocated->pointer == 0 && pool->size == 0 ) {
+ return 0;
+ }
+ }
+ }
+ else {
+ sprintf(buffer,"free buffer found. Wasted %d bytes\n", pool->buffers[(pool->start+bestfit)%MAX_FREE_GPU_BUFFERS]->size-size);
+ DEBUG_VBO(buffer);
+
+ allocated = pool->buffers[(pool->start+bestfit)%MAX_FREE_GPU_BUFFERS];
+ GPU_buffer_pool_remove(bestfit,pool);
+ }
+ return allocated;
+}
+
+void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool )
+{
+ int place;
+
+ DEBUG_VBO("GPU_buffer_free\n");
+
+ if( buffer == 0 )
+ return;
+ if( pool == 0 )
+ pool = globalPool;
+ if( pool == 0 )
+ globalPool = GPU_buffer_pool_new();
+
+ while( pool->start < 0 )
+ pool->start += MAX_FREE_GPU_BUFFERS;
+ place = (pool->start-1 + MAX_FREE_GPU_BUFFERS)%MAX_FREE_GPU_BUFFERS;
+
+ /* free the last used buffer in the queue if no more space */
+ if( pool->size == MAX_FREE_GPU_BUFFERS ) {
+ GPU_buffer_pool_delete_last( pool );
+ }
+
+ pool->size++;
+ pool->start = place;
+ pool->buffers[place] = buffer;
+}
+
+GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
+{
+ GPUDrawObject *object;
+ MVert *mvert;
+ MFace *mface;
+ int numverts[32768]; /* material number is an 16-bit short so there's at most 32768 materials */
+ int redir[32768]; /* material number is an 16-bit short so there's at most 32768 materials */
+ int *index;
+ int i;
+ int curmat, curverts, numfaces;
+
+ DEBUG_VBO("GPU_drawobject_new\n");
+
+ object = MEM_callocN(sizeof(GPUDrawObject),"GPU_drawobject_new_object");
+ object->nindices = dm->getNumVerts(dm);
+ object->indices = MEM_mallocN(sizeof(IndexLink)*object->nindices, "GPU_drawobject_new_indices");
+ object->nedges = dm->getNumEdges(dm);
+
+ for( i = 0; i < object->nindices; i++ ) {
+ object->indices[i].element = -1;
+ object->indices[i].next = 0;
+ }
+ /*object->legacy = 1;*/
+ memset(numverts,0,sizeof(int)*32768);
+
+ mvert = dm->getVertArray(dm);
+ mface = dm->getTessFaceArray(dm);
+
+ numfaces= dm->getNumTessFaces(dm);
+ for( i=0; i < numfaces; i++ ) {
+ if( mface[i].v4 )
+ numverts[mface[i].mat_nr+16383] += 6; /* split every quad into two triangles */
+ else
+ numverts[mface[i].mat_nr+16383] += 3;
+ }
+
+ for( i = 0; i < 32768; i++ ) {
+ if( numverts[i] > 0 ) {
+ object->nmaterials++;
+ object->nelements += numverts[i];
+ }
+ }
+ object->materials = MEM_mallocN(sizeof(GPUBufferMaterial)*object->nmaterials,"GPU_drawobject_new_materials");
+ index = MEM_mallocN(sizeof(int)*object->nmaterials,"GPU_drawobject_new_index");
+
+ curmat = curverts = 0;
+ for( i = 0; i < 32768; i++ ) {
+ if( numverts[i] > 0 ) {
+ object->materials[curmat].mat_nr = i-16383;
+ object->materials[curmat].start = curverts;
+ index[curmat] = curverts/3;
+ object->materials[curmat].end = curverts+numverts[i];
+ curverts += numverts[i];
+ curmat++;
+ }
+ }
+ object->faceRemap = MEM_mallocN(sizeof(int)*object->nelements/3,"GPU_drawobject_new_faceRemap");
+ for( i = 0; i < object->nmaterials; i++ ) {
+ redir[object->materials[i].mat_nr+16383] = i; /* material number -> material index */
+ }
+
+ object->indexMem = MEM_callocN(sizeof(IndexLink)*object->nelements,"GPU_drawobject_new_indexMem");
+ object->indexMemUsage = 0;
+
+#define ADDLINK( INDEX, ACTUAL ) \
+ if( object->indices[INDEX].element == -1 ) { \
+ object->indices[INDEX].element = ACTUAL; \
+ } else { \
+ IndexLink *lnk = &object->indices[INDEX], *lnk2; \
+ lnk2 = &object->indexMem[object->indexMemUsage]; \
+ lnk2->element = ACTUAL; \
+ SWAP(IndexLink, *lnk, *lnk2); \
+ lnk->next = lnk2; \
+ object->indexMemUsage++; \
+ }
+
+ for( i=0; i < numfaces; i++ ) {
+ int curInd = index[redir[mface[i].mat_nr+16383]];
+ object->faceRemap[curInd] = i;
+ ADDLINK( mface[i].v1, curInd*3 );
+ ADDLINK( mface[i].v2, curInd*3+1 );
+ ADDLINK( mface[i].v3, curInd*3+2 );
+ if( mface[i].v4 ) {
+ object->faceRemap[curInd+1] = i;
+ ADDLINK( mface[i].v3, curInd*3+3 );
+ ADDLINK( mface[i].v4, curInd*3+4 );
+ ADDLINK( mface[i].v1, curInd*3+5 );
+
+ index[redir[mface[i].mat_nr+16383]]+=2;
+ }
+ else {
+ index[redir[mface[i].mat_nr+16383]]++;
+ }
+ }
+
+ for( i = 0; i < object->nindices; i++ ) {
+ if( object->indices[i].element == -1 ) {
+ object->indices[i].element = object->nelements + object->nlooseverts;
+ object->nlooseverts++;
+ }
+ }
+#undef ADDLINK
+
+ MEM_freeN(index);
+ return object;
+}
+
+void GPU_drawobject_free( DerivedMesh *dm )
+{
+ GPUDrawObject *object;
+
+ DEBUG_VBO("GPU_drawobject_free\n");
+
+ if( dm == 0 )
+ return;
+ object = dm->drawObject;
+ if( object == 0 )
+ return;
+
+ MEM_freeN(object->materials);
+ MEM_freeN(object->faceRemap);
+ MEM_freeN(object->indices);
+ MEM_freeN(object->indexMem);
+ GPU_buffer_free( object->vertices, globalPool );
+ GPU_buffer_free( object->normals, globalPool );
+ GPU_buffer_free( object->uv, globalPool );
+ GPU_buffer_free( object->colors, globalPool );
+ GPU_buffer_free( object->edges, globalPool );
+ GPU_buffer_free( object->uvedges, globalPool );
+
+ MEM_freeN(object);
+ dm->drawObject = 0;
+}
+
+GPUBuffer *GPU_buffer_setup( DerivedMesh *dm, GPUDrawObject *object, int size, GLenum target, void *user, void (*copy_f)(DerivedMesh *, float *, int *, int *, void *) )
+{
+ GPUBuffer *buffer;
+ float *varray;
+ int redir[32768];
+ int *index;
+ int i;
+ int success;
+ GLboolean uploaded;
+
+ DEBUG_VBO("GPU_buffer_setup\n");
+
+ if( globalPool == 0 ) {
+ globalPool = GPU_buffer_pool_new();
+
+ /* somehow GL_NORMAL_ARRAY is enabled on startup and causes edge drawing code to crash */
+ glDisableClientState( GL_VERTEX_ARRAY );
+ glDisableClientState( GL_NORMAL_ARRAY );
+ glDisableClientState( GL_TEXTURE_COORD_ARRAY );
+ glDisableClientState( GL_COLOR_ARRAY );
+ }
+ buffer = GPU_buffer_alloc(size,globalPool);
+ if( buffer == 0 ) {
+ dm->drawObject->legacy = 1;
+ }
+ if( dm->drawObject->legacy ) {
+ return 0;
+ }
+
+ index = MEM_mallocN(sizeof(int)*object->nmaterials,"GPU_buffer_setup");
+ for( i = 0; i < object->nmaterials; i++ ) {
+ index[i] = object->materials[i].start*3;
+ redir[object->materials[i].mat_nr+16383] = i;
+ }
+
+ if( useVBOs ) {
+ success = 0;
+ while( success == 0 ) {
+ glBindBufferARB( target, buffer->id );
+ glBufferDataARB( target, buffer->size, 0, GL_STATIC_DRAW_ARB ); /* discard previous data, avoid stalling gpu */
+ varray = glMapBufferARB( target, GL_WRITE_ONLY_ARB );
+ if( varray == 0 ) {
+ DEBUG_VBO( "Failed to map buffer to client address space\n" );
+ GPU_buffer_free( buffer, globalPool );
+ GPU_buffer_pool_delete_last( globalPool );
+ if( globalPool->size > 0 ) {
+ GPU_buffer_pool_delete_last( globalPool );
+ buffer = GPU_buffer_alloc( size, globalPool );
+ if( buffer == 0 ) {
+ dm->drawObject->legacy = 1;
+ success = 1;
+ }
+ }
+ else {
+ dm->drawObject->legacy = 1;
+ success = 1;
+ }
+ }
+ else {
+ success = 1;
+ }
+ }
+
+ if( dm->drawObject->legacy == 0 ) {
+ uploaded = GL_FALSE;
+ while( !uploaded ) {
+ (*copy_f)( dm, varray, index, redir, user );
+ uploaded = glUnmapBufferARB( target ); /* returns false if data got corruped during transfer */
+ }
+ }
+ glBindBufferARB(target, 0);
+ }
+ else {
+ if( buffer->pointer != 0 ) {
+ varray = buffer->pointer;
+ (*copy_f)( dm, varray, index, redir, user );
+ }
+ else {
+ dm->drawObject->legacy = 1;
+ }
+ }
+
+ MEM_freeN(index);
+
+ return buffer;
+}
+
+void GPU_buffer_copy_vertex( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+{
+ int start;
+ int i, j, numfaces;
+
+ MVert *mvert;
+ MFace *mface;
+
+ DEBUG_VBO("GPU_buffer_copy_vertex\n");
+
+ mvert = dm->getVertArray(dm);
+ mface = dm->getTessFaceArray(dm);
+
+ numfaces= dm->getNumTessFaces(dm);
+ for( i=0; i < numfaces; i++ ) {
+ start = index[redir[mface[i].mat_nr+16383]];
+ if( mface[i].v4 )
+ index[redir[mface[i].mat_nr+16383]] += 18;
+ else
+ index[redir[mface[i].mat_nr+16383]] += 9;
+
+ /* v1 v2 v3 */
+ VECCOPY(&varray[start],mvert[mface[i].v1].co);
+ VECCOPY(&varray[start+3],mvert[mface[i].v2].co);
+ VECCOPY(&varray[start+6],mvert[mface[i].v3].co);
+
+ if( mface[i].v4 ) {
+ /* v3 v4 v1 */
+ VECCOPY(&varray[start+9],mvert[mface[i].v3].co);
+ VECCOPY(&varray[start+12],mvert[mface[i].v4].co);
+ VECCOPY(&varray[start+15],mvert[mface[i].v1].co);
+ }
+ }
+ j = dm->drawObject->nelements*3;
+ for( i = 0; i < dm->drawObject->nindices; i++ ) {
+ if( dm->drawObject->indices[i].element >= dm->drawObject->nelements ) {
+ VECCOPY(&varray[j],mvert[i].co);
+ j+=3;
+ }
+ }
+}
+
+GPUBuffer *GPU_buffer_vertex( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_buffer_vertex\n");
+
+ return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*3*(dm->drawObject->nelements+dm->drawObject->nlooseverts), GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_vertex);
+}
+
+void GPU_buffer_copy_normal( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+{
+ int i, numfaces;
+ int start;
+ float norm[3];
+
+ float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
+ MVert *mvert = dm->getVertArray(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
+
+ DEBUG_VBO("GPU_buffer_copy_normal\n");
+
+ numfaces= dm->getNumTessFaces(dm);
+ for( i=0; i < numfaces; i++ ) {
+ start = index[redir[mface[i].mat_nr+16383]];
+ if( mface[i].v4 )
+ index[redir[mface[i].mat_nr+16383]] += 18;
+ else
+ index[redir[mface[i].mat_nr+16383]] += 9;
+
+ /* v1 v2 v3 */
+ if( mface[i].flag & ME_SMOOTH ) {
+ VECCOPY(&varray[start],mvert[mface[i].v1].no);
+ VECCOPY(&varray[start+3],mvert[mface[i].v2].no);
+ VECCOPY(&varray[start+6],mvert[mface[i].v3].no);
+ }
+ else {
+ if( nors ) {
+ VECCOPY(&varray[start],&nors[i*3]);
+ VECCOPY(&varray[start+3],&nors[i*3]);
+ VECCOPY(&varray[start+6],&nors[i*3]);
+ }
+ if( mface[i].v4 )
+ CalcNormFloat4(mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co, mvert[mface[i].v4].co, norm);
+ else
+ CalcNormFloat(mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co, norm);
+ VECCOPY(&varray[start],norm);
+ VECCOPY(&varray[start+3],norm);
+ VECCOPY(&varray[start+6],norm);
+ }
+
+ if( mface[i].v4 ) {
+ /* v3 v4 v1 */
+ if( mface[i].flag & ME_SMOOTH ) {
+ VECCOPY(&varray[start+9],mvert[mface[i].v3].no);
+ VECCOPY(&varray[start+12],mvert[mface[i].v4].no);
+ VECCOPY(&varray[start+15],mvert[mface[i].v1].no);
+ }
+ else {
+ VECCOPY(&varray[start+9],norm);
+ VECCOPY(&varray[start+12],norm);
+ VECCOPY(&varray[start+15],norm);
+ }
+ }
+ }
+}
+
+GPUBuffer *GPU_buffer_normal( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_buffer_normal\n");
+
+ return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_normal);
+}
+
+void GPU_buffer_copy_uv( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+{
+ int start;
+ int i, numfaces;
+
+ MTFace *mtface;
+ MFace *mface;
+
+ DEBUG_VBO("GPU_buffer_copy_uv\n");
+
+ mface = dm->getTessFaceArray(dm);
+ mtface = DM_get_face_data_layer(dm, CD_MTFACE);
+
+ if( mtface == 0 ) {
+ DEBUG_VBO("Texture coordinates do not exist for this mesh");
+ return;
+ }
+
+ numfaces= dm->getNumTessFaces(dm);
+ for( i=0; i < numfaces; i++ ) {
+ start = index[redir[mface[i].mat_nr+16383]];
+ if( mface[i].v4 )
+ index[redir[mface[i].mat_nr+16383]] += 12;
+ else
+ index[redir[mface[i].mat_nr+16383]] += 6;
+
+ /* v1 v2 v3 */
+ VECCOPY2D(&varray[start],mtface[i].uv[0]);
+ VECCOPY2D(&varray[start+2],mtface[i].uv[1]);
+ VECCOPY2D(&varray[start+4],mtface[i].uv[2]);
+
+ if( mface[i].v4 ) {
+ /* v3 v4 v1 */
+ VECCOPY2D(&varray[start+6],mtface[i].uv[2]);
+ VECCOPY2D(&varray[start+8],mtface[i].uv[3]);
+ VECCOPY2D(&varray[start+10],mtface[i].uv[0]);
+ }
+ }
+}
+
+GPUBuffer *GPU_buffer_uv( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_buffer_uv\n");
+ if( DM_get_face_data_layer(dm, CD_MTFACE) != 0 )
+ return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*2*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uv);
+ else
+ return 0;
+}
+
+void GPU_buffer_copy_color3( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
+{
+ int i, numfaces;
+ unsigned char *varray = (unsigned char *)varray_;
+ unsigned char *mcol = (unsigned char *)user;
+ MFace *mface = dm->getTessFaceArray(dm);
+
+ DEBUG_VBO("GPU_buffer_copy_color3\n");
+
+ numfaces= dm->getNumTessFaces(dm);
+ for( i=0; i < numfaces; i++ ) {
+ int start = index[redir[mface[i].mat_nr+16383]];
+ if( mface[i].v4 )
+ index[redir[mface[i].mat_nr+16383]] += 18;
+ else
+ index[redir[mface[i].mat_nr+16383]] += 9;
+
+ /* v1 v2 v3 */
+ VECCOPY(&varray[start],&mcol[i*12]);
+ VECCOPY(&varray[start+3],&mcol[i*12+3]);
+ VECCOPY(&varray[start+6],&mcol[i*12+6]);
+ if( mface[i].v4 ) {
+ /* v3 v4 v1 */
+ VECCOPY(&varray[start+9],&mcol[i*12+6]);
+ VECCOPY(&varray[start+12],&mcol[i*12+9]);
+ VECCOPY(&varray[start+15],&mcol[i*12]);
+ }
+ }
+}
+
+void GPU_buffer_copy_color4( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
+{
+ int i, numfaces;
+ unsigned char *varray = (unsigned char *)varray_;
+ unsigned char *mcol = (unsigned char *)user;
+ MFace *mface = dm->getTessFaceArray(dm);
+
+ DEBUG_VBO("GPU_buffer_copy_color4\n");
+
+ numfaces= dm->getNumTessFaces(dm);
+ for( i=0; i < numfaces; i++ ) {
+ int start = index[redir[mface[i].mat_nr+16383]];
+ if( mface[i].v4 )
+ index[redir[mface[i].mat_nr+16383]] += 18;
+ else
+ index[redir[mface[i].mat_nr+16383]] += 9;
+
+ /* v1 v2 v3 */
+ VECCOPY(&varray[start],&mcol[i*16]);
+ VECCOPY(&varray[start+3],&mcol[i*16+4]);
+ VECCOPY(&varray[start+6],&mcol[i*16+8]);
+ if( mface[i].v4 ) {
+ /* v3 v4 v1 */
+ VECCOPY(&varray[start+9],&mcol[i*16+8]);
+ VECCOPY(&varray[start+12],&mcol[i*16+12]);
+ VECCOPY(&varray[start+15],&mcol[i*16]);
+ }
+ }
+}
+
+GPUBuffer *GPU_buffer_color( DerivedMesh *dm )
+{
+ unsigned char *colors;
+ int i, numfaces;
+ MCol *mcol;
+ GPUBuffer *result;
+ DEBUG_VBO("GPU_buffer_color\n");
+
+ mcol = DM_get_face_data_layer(dm, CD_ID_MCOL);
+ dm->drawObject->colType = CD_ID_MCOL;
+ if(!mcol) {
+ mcol = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
+ dm->drawObject->colType = CD_WEIGHT_MCOL;
+ }
+ if(!mcol) {
+ mcol = DM_get_face_data_layer(dm, CD_MCOL);
+ dm->drawObject->colType = CD_MCOL;
+ }
+
+ numfaces= dm->getNumTessFaces(dm);
+ colors = MEM_mallocN(numfaces*12*sizeof(unsigned char), "GPU_buffer_color");
+ for( i=0; i < numfaces*4; i++ ) {
+ colors[i*3] = mcol[i].b;
+ colors[i*3+1] = mcol[i].g;
+ colors[i*3+2] = mcol[i].r;
+ }
+
+ result = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, colors, GPU_buffer_copy_color3 );
+
+ MEM_freeN(colors);
+ return result;
+}
+
+void GPU_buffer_copy_edge( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+{
+ int i;
+
+ MVert *mvert;
+ MEdge *medge;
+ unsigned int *varray_ = (unsigned int *)varray;
+ int numedges;
+
+ DEBUG_VBO("GPU_buffer_copy_edge\n");
+
+ mvert = dm->getVertArray(dm);
+ medge = dm->getEdgeArray(dm);
+
+ numedges= dm->getNumEdges(dm);
+ for(i = 0; i < numedges; i++) {
+ varray_[i*2] = (unsigned int)dm->drawObject->indices[medge[i].v1].element;
+ varray_[i*2+1] = (unsigned int)dm->drawObject->indices[medge[i].v2].element;
+ }
+}
+
+GPUBuffer *GPU_buffer_edge( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_buffer_edge\n");
+
+ return GPU_buffer_setup( dm, dm->drawObject, sizeof(int)*2*dm->drawObject->nedges, GL_ELEMENT_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_edge);
+}
+
+void GPU_buffer_copy_uvedge( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+{
+ MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
+ int i, j=0;
+
+ DEBUG_VBO("GPU_buffer_copy_uvedge\n");
+
+ if(tf) {
+ for(i = 0; i < dm->numFaceData; i++, tf++) {
+ MFace mf;
+ dm->getTessFace(dm,i,&mf);
+
+ VECCOPY2D(&varray[j],tf->uv[0]);
+ VECCOPY2D(&varray[j+2],tf->uv[1]);
+
+ VECCOPY2D(&varray[j+4],tf->uv[1]);
+ VECCOPY2D(&varray[j+6],tf->uv[2]);
+
+ if(!mf.v4) {
+ VECCOPY2D(&varray[j+8],tf->uv[2]);
+ VECCOPY2D(&varray[j+10],tf->uv[0]);
+ j+=12;
+ } else {
+ VECCOPY2D(&varray[j+8],tf->uv[2]);
+ VECCOPY2D(&varray[j+10],tf->uv[3]);
+
+ VECCOPY2D(&varray[j+12],tf->uv[3]);
+ VECCOPY2D(&varray[j+14],tf->uv[0]);
+ j+=16;
+ }
+ }
+ }
+ else {
+ DEBUG_VBO("Could not get MTFACE data layer");
+ }
+}
+
+GPUBuffer *GPU_buffer_uvedge( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_buffer_uvedge\n");
+
+ return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*2*(dm->drawObject->nelements/3)*2, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uvedge);
+}
+
+
+void GPU_vertex_setup( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_vertex_setup\n");
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new( dm );
+ if( dm->drawObject->vertices == 0 )
+ dm->drawObject->vertices = GPU_buffer_vertex( dm );
+ if( dm->drawObject->vertices == 0 ) {
+ DEBUG_VBO( "Failed to setup vertices\n" );
+ return;
+ }
+
+ glEnableClientState( GL_VERTEX_ARRAY );
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->vertices->id );
+ glVertexPointer( 3, GL_FLOAT, 0, 0 );
+ }
+ else {
+ glVertexPointer( 3, GL_FLOAT, 0, dm->drawObject->vertices->pointer );
+ }
+
+ GLStates |= GPU_BUFFER_VERTEX_STATE;
+}
+
+void GPU_normal_setup( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_normal_setup\n");
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new( dm );
+ if( dm->drawObject->normals == 0 )
+ dm->drawObject->normals = GPU_buffer_normal( dm );
+ if( dm->drawObject->normals == 0 ) {
+ DEBUG_VBO( "Failed to setup normals\n" );
+ return;
+ }
+ glEnableClientState( GL_NORMAL_ARRAY );
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->normals->id );
+ glNormalPointer( GL_FLOAT, 0, 0 );
+ }
+ else {
+ glNormalPointer( GL_FLOAT, 0, dm->drawObject->normals->pointer );
+ }
+
+ GLStates |= GPU_BUFFER_NORMAL_STATE;
+}
+
+void GPU_uv_setup( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_uv_setup\n");
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new( dm );
+ if( dm->drawObject->uv == 0 )
+ dm->drawObject->uv = GPU_buffer_uv( dm );
+
+ if( dm->drawObject->uv != 0 ) {
+ glEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id );
+ glTexCoordPointer( 2, GL_FLOAT, 0, 0 );
+ }
+ else {
+ glTexCoordPointer( 2, GL_FLOAT, 0, dm->drawObject->uv->pointer );
+ }
+
+ GLStates |= GPU_BUFFER_TEXCOORD_STATE;
+ }
+}
+
+void GPU_color_setup( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_color_setup\n");
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new( dm );
+ if( dm->drawObject->colors == 0 )
+ dm->drawObject->colors = GPU_buffer_color( dm );
+ if( dm->drawObject->colors == 0 ) {
+ DEBUG_VBO( "Failed to setup colors\n" );
+ return;
+ }
+ glEnableClientState( GL_COLOR_ARRAY );
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->colors->id );
+ glColorPointer( 3, GL_UNSIGNED_BYTE, 0, 0 );
+ }
+ else {
+ glColorPointer( 3, GL_UNSIGNED_BYTE, 0, dm->drawObject->colors->pointer );
+ }
+
+ GLStates |= GPU_BUFFER_COLOR_STATE;
+}
+
+void GPU_edge_setup( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_edge_setup\n");
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new( dm );
+ if( dm->drawObject->edges == 0 )
+ dm->drawObject->edges = GPU_buffer_edge( dm );
+ if( dm->drawObject->edges == 0 ) {
+ DEBUG_VBO( "Failed to setup edges\n" );
+ return;
+ }
+ if( dm->drawObject->vertices == 0 )
+ dm->drawObject->vertices = GPU_buffer_vertex( dm );
+ if( dm->drawObject->vertices == 0 ) {
+ DEBUG_VBO( "Failed to setup vertices\n" );
+ return;
+ }
+
+ glEnableClientState( GL_VERTEX_ARRAY );
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->vertices->id );
+ glVertexPointer( 3, GL_FLOAT, 0, 0 );
+ }
+ else {
+ glVertexPointer( 3, GL_FLOAT, 0, dm->drawObject->vertices->pointer );
+ }
+
+ GLStates |= GPU_BUFFER_VERTEX_STATE;
+
+ if( useVBOs ) {
+ glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->edges->id );
+ }
+
+ GLStates |= GPU_BUFFER_ELEMENT_STATE;
+}
+
+void GPU_uvedge_setup( DerivedMesh *dm )
+{
+ DEBUG_VBO("GPU_uvedge_setup\n");
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new( dm );
+ if( dm->drawObject->uvedges == 0 )
+ dm->drawObject->uvedges = GPU_buffer_uvedge( dm );
+ if( dm->drawObject->uvedges == 0 ) {
+ DEBUG_VBO( "Failed to setup UV edges\n" );
+ return;
+ }
+
+ glEnableClientState( GL_VERTEX_ARRAY );
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->uvedges->id );
+ glVertexPointer( 2, GL_FLOAT, 0, 0 );
+ }
+ else {
+ glVertexPointer( 2, GL_FLOAT, 0, dm->drawObject->uvedges->pointer );
+ }
+
+ GLStates |= GPU_BUFFER_VERTEX_STATE;
+}
+
+void GPU_interleaved_setup( GPUBuffer *buffer, int data[] ) {
+ int i;
+ int elementsize = 0;
+ intptr_t offset = 0;
+
+ DEBUG_VBO("GPU_interleaved_setup\n");
+
+ for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
+ switch( data[i] ) {
+ case GPU_BUFFER_INTER_V3F:
+ elementsize += 3*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_N3F:
+ elementsize += 3*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_T2F:
+ elementsize += 2*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_C3UB:
+ elementsize += 3*sizeof(unsigned char);
+ break;
+ case GPU_BUFFER_INTER_C4UB:
+ elementsize += 4*sizeof(unsigned char);
+ break;
+ default:
+ DEBUG_VBO( "Unknown element in data type array in GPU_interleaved_setup\n" );
+ }
+ }
+
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
+ for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
+ switch( data[i] ) {
+ case GPU_BUFFER_INTER_V3F:
+ glEnableClientState( GL_VERTEX_ARRAY );
+ glVertexPointer( 3, GL_FLOAT, elementsize, (void *)offset );
+ GLStates |= GPU_BUFFER_VERTEX_STATE;
+ offset += 3*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_N3F:
+ glEnableClientState( GL_NORMAL_ARRAY );
+ glNormalPointer( GL_FLOAT, elementsize, (void *)offset );
+ GLStates |= GPU_BUFFER_NORMAL_STATE;
+ offset += 3*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_T2F:
+ glEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ glTexCoordPointer( 2, GL_FLOAT, elementsize, (void *)offset );
+ GLStates |= GPU_BUFFER_TEXCOORD_STATE;
+ offset += 2*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_C3UB:
+ glEnableClientState( GL_COLOR_ARRAY );
+ glColorPointer( 3, GL_UNSIGNED_BYTE, elementsize, (void *)offset );
+ GLStates |= GPU_BUFFER_COLOR_STATE;
+ offset += 3*sizeof(unsigned char);
+ break;
+ case GPU_BUFFER_INTER_C4UB:
+ glEnableClientState( GL_COLOR_ARRAY );
+ glColorPointer( 4, GL_UNSIGNED_BYTE, elementsize, (void *)offset );
+ GLStates |= GPU_BUFFER_COLOR_STATE;
+ offset += 4*sizeof(unsigned char);
+ break;
+ }
+ }
+ }
+ else {
+ for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
+ switch( data[i] ) {
+ case GPU_BUFFER_INTER_V3F:
+ glEnableClientState( GL_VERTEX_ARRAY );
+ glVertexPointer( 3, GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
+ GLStates |= GPU_BUFFER_VERTEX_STATE;
+ offset += 3*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_N3F:
+ glEnableClientState( GL_NORMAL_ARRAY );
+ glNormalPointer( GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
+ GLStates |= GPU_BUFFER_NORMAL_STATE;
+ offset += 3*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_T2F:
+ glEnableClientState( GL_TEXTURE_COORD_ARRAY );
+ glTexCoordPointer( 2, GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
+ GLStates |= GPU_BUFFER_TEXCOORD_STATE;
+ offset += 2*sizeof(float);
+ break;
+ case GPU_BUFFER_INTER_C3UB:
+ glEnableClientState( GL_COLOR_ARRAY );
+ glColorPointer( 3, GL_UNSIGNED_BYTE, elementsize, offset+(char *)buffer->pointer );
+ GLStates |= GPU_BUFFER_COLOR_STATE;
+ offset += 3*sizeof(unsigned char);
+ break;
+ case GPU_BUFFER_INTER_C4UB:
+ glEnableClientState( GL_COLOR_ARRAY );
+ glColorPointer( 4, GL_UNSIGNED_BYTE, elementsize, offset+(char *)buffer->pointer );
+ GLStates |= GPU_BUFFER_COLOR_STATE;
+ offset += 4*sizeof(unsigned char);
+ break;
+ }
+ }
+ }
+}
+
+static int GPU_typesize( int type ) {
+ switch( type ) {
+ case GL_FLOAT:
+ return sizeof(float);
+ case GL_INT:
+ return sizeof(int);
+ case GL_UNSIGNED_INT:
+ return sizeof(unsigned int);
+ case GL_BYTE:
+ return sizeof(char);
+ case GL_UNSIGNED_BYTE:
+ return sizeof(unsigned char);
+ default:
+ return 0;
+ }
+}
+
+int GPU_attrib_element_size( GPUAttrib data[], int numdata ) {
+ int i, elementsize = 0;
+
+ for( i = 0; i < numdata; i++ ) {
+ int typesize = GPU_typesize(data[i].type);
+ if( typesize == 0 )
+ DEBUG_VBO( "Unknown element in data type array in GPU_attrib_element_size\n" );
+ else {
+ elementsize += typesize*data[i].size;
+ }
+ }
+ return elementsize;
+}
+
+void GPU_interleaved_attrib_setup( GPUBuffer *buffer, GPUAttrib data[], int numdata ) {
+ int i;
+ int elementsize;
+ intptr_t offset = 0;
+
+ DEBUG_VBO("GPU_interleaved_attrib_setup\n");
+
+ for( i = 0; i < MAX_GPU_ATTRIB_DATA; i++ ) {
+ if( attribData[i].index != -1 ) {
+ glDisableVertexAttribArrayARB( attribData[i].index );
+ }
+ else
+ break;
+ }
+ elementsize = GPU_attrib_element_size( data, numdata );
+
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
+ for( i = 0; i < numdata; i++ ) {
+ glEnableVertexAttribArrayARB( data[i].index );
+ glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_TRUE, elementsize, (void *)offset );
+ offset += data[i].size*GPU_typesize(data[i].type);
+
+ attribData[i].index = data[i].index;
+ attribData[i].size = data[i].size;
+ attribData[i].type = data[i].type;
+ }
+ attribData[numdata].index = -1;
+ }
+ else {
+ for( i = 0; i < numdata; i++ ) {
+ glEnableVertexAttribArrayARB( data[i].index );
+ glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_TRUE, elementsize, (char *)buffer->pointer + offset );
+ offset += data[i].size*GPU_typesize(data[i].type);
+ }
+ }
+}
+
+
+void GPU_buffer_unbind()
+{
+ int i;
+ DEBUG_VBO("GPU_buffer_unbind\n");
+
+ if( GLStates & GPU_BUFFER_VERTEX_STATE )
+ glDisableClientState( GL_VERTEX_ARRAY );
+ if( GLStates & GPU_BUFFER_NORMAL_STATE )
+ glDisableClientState( GL_NORMAL_ARRAY );
+ if( GLStates & GPU_BUFFER_TEXCOORD_STATE )
+ glDisableClientState( GL_TEXTURE_COORD_ARRAY );
+ if( GLStates & GPU_BUFFER_COLOR_STATE )
+ glDisableClientState( GL_COLOR_ARRAY );
+ if( GLStates & GPU_BUFFER_ELEMENT_STATE ) {
+ if( useVBOs ) {
+ glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
+ }
+ }
+ GLStates &= !(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE | GPU_BUFFER_TEXCOORD_STATE | GPU_BUFFER_COLOR_STATE | GPU_BUFFER_ELEMENT_STATE);
+
+ for( i = 0; i < MAX_GPU_ATTRIB_DATA; i++ ) {
+ if( attribData[i].index != -1 ) {
+ glDisableVertexAttribArrayARB( attribData[i].index );
+ }
+ else
+ break;
+ }
+ if( GLStates != 0 )
+ DEBUG_VBO( "Some weird OpenGL state is still set. Why?" );
+ if( useVBOs )
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
+}
+
+void GPU_color3_upload( DerivedMesh *dm, unsigned char *data )
+{
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new(dm);
+ GPU_buffer_free(dm->drawObject->colors,globalPool);
+ dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color3 );
+}
+void GPU_color4_upload( DerivedMesh *dm, unsigned char *data )
+{
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new(dm);
+ GPU_buffer_free(dm->drawObject->colors,globalPool);
+ dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color4 );
+}
+
+void GPU_color_switch( int mode )
+{
+ if( mode ) {
+ if( !GLStates & GPU_BUFFER_COLOR_STATE )
+ glEnableClientState( GL_COLOR_ARRAY );
+ GLStates |= GPU_BUFFER_COLOR_STATE;
+ }
+ else {
+ if( GLStates & GPU_BUFFER_COLOR_STATE )
+ glDisableClientState( GL_COLOR_ARRAY );
+ GLStates &= (!GPU_BUFFER_COLOR_STATE);
+ }
+}
+
+int GPU_buffer_legacy( DerivedMesh *dm )
+{
+ int test= (U.gameflags & USER_DISABLE_VBO);
+ if( test )
+ return 1;
+
+ if( dm->drawObject == 0 )
+ dm->drawObject = GPU_drawobject_new(dm);
+ return dm->drawObject->legacy;
+}
+
+void *GPU_buffer_lock( GPUBuffer *buffer )
+{
+ float *varray;
+
+ DEBUG_VBO("GPU_buffer_lock\n");
+ if( buffer == 0 ) {
+ DEBUG_VBO( "Failed to lock NULL buffer\n" );
+ return 0;
+ }
+
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
+ varray = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
+ if( varray == 0 ) {
+ DEBUG_VBO( "Failed to map buffer to client address space\n" );
+ }
+ return varray;
+ }
+ else {
+ return buffer->pointer;
+ }
+}
+
+void *GPU_buffer_lock_stream( GPUBuffer *buffer )
+{
+ float *varray;
+
+ DEBUG_VBO("GPU_buffer_lock_stream\n");
+ if( buffer == 0 ) {
+ DEBUG_VBO( "Failed to lock NULL buffer\n" );
+ return 0;
+ }
+
+ if( useVBOs ) {
+ glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
+ glBufferDataARB( GL_ARRAY_BUFFER_ARB, buffer->size, 0, GL_STREAM_DRAW_ARB ); /* discard previous data, avoid stalling gpu */
+ varray = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
+ if( varray == 0 ) {
+ DEBUG_VBO( "Failed to map buffer to client address space\n" );
+ }
+ return varray;
+ }
+ else {
+ return buffer->pointer;
+ }
+}
+
+void GPU_buffer_unlock( GPUBuffer *buffer )
+{
+ DEBUG_VBO( "GPU_buffer_unlock\n" );
+ if( useVBOs ) {
+ if( buffer != 0 ) {
+ if( glUnmapBufferARB( GL_ARRAY_BUFFER_ARB ) == 0 ) {
+ DEBUG_VBO( "Failed to copy new data\n" );
+ }
+ }
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ }
+}
+
+void GPU_buffer_draw_elements( GPUBuffer *elements, unsigned int mode, int start, int count )
+{
+ if( useVBOs ) {
+ glDrawElements( mode, count, GL_UNSIGNED_INT, (void *)(start*sizeof(unsigned int)) );
+ }
+ else {
+ glDrawElements( mode, count, GL_UNSIGNED_INT, ((int *)elements->pointer)+start );
+ }
+}
diff --git a/source/blender/makesrna/intern/rna_action_api.c b/source/blender/makesrna/intern/rna_action_api.c
new file mode 100644
index 00000000000..991a8251cc5
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_action_api.c
@@ -0,0 +1,80 @@
+/**
+ * ***** 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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Arystanbek Dyussenov
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "RNA_define.h"
+#include "RNA_types.h"
+
+#include "DNA_action_types.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_action.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_curve_types.h"
+
+/* XXX disabled until RNA allows returning arrays */
+#if 0
+/* return frame range of all curves (min, max) or (0, 1) if there are no keys */
+int *rna_Action_get_frame_range(bAction *act, int *ret_length)
+{
+ int *ret;
+ float start, end;
+
+ calc_action_range(act, &start, &end, 1);
+
+ *ret_length= 2;
+ ret= MEM_callocN(*ret_length * sizeof(int), "rna_Action_get_frame_range");
+
+ ret[0]= (int)start;
+ ret[1]= (int)end;
+
+ return ret;
+}
+#endif
+
+#else
+
+void RNA_api_action(StructRNA *srna)
+{
+#if 0
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ func= RNA_def_function(srna, "get_frame_range", "rna_Action_get_frame_range");
+ RNA_def_function_ui_description(func, "Get action frame range as a (min, max) tuple.");
+ parm= RNA_def_int_array(func, "frame_range", 1, NULL, 0, 0, "", "Action frame range.", 0, 0);
+ RNA_def_property_flag(parm, PROP_DYNAMIC_ARRAY);
+ RNA_def_function_return(func, parm);
+#endif
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
new file mode 100644
index 00000000000..4ac6b98b167
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -0,0 +1,101 @@
+/**
+ * $Id: rna_image_api.c 23507 2009-09-27 09:19:29Z kazanbas $
+ *
+ * ***** 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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Arystanbek Dyussenov
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "RNA_define.h"
+#include "RNA_types.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_utildefines.h"
+
+#include "DNA_image_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+/*
+ User should check if returned path exists before copying a file there.
+
+ TODO: it would be better to return a (abs, rel) tuple.
+*/
+static char *rna_Image_get_export_path(Image *image, char *dest_dir, int rel)
+{
+ int length = FILE_MAX;
+ char *path= MEM_callocN(length, "image file path");
+
+ if (!BKE_get_image_export_path(image, dest_dir, rel ? NULL : path, length, rel ? path : NULL, length )) {
+ MEM_freeN(path);
+ return NULL;
+ }
+
+ return path;
+}
+
+char *rna_Image_get_abs_filename(Image *image, bContext *C)
+{
+ char *filename= MEM_callocN(FILE_MAX, "Image.get_abs_filename()");
+
+ BLI_strncpy(filename, image->name, FILE_MAXDIR + FILE_MAXFILE);
+ BLI_convertstringcode(filename, CTX_data_main(C)->name);
+ BLI_convertstringframe(filename, CTX_data_scene(C)->r.cfra);
+
+ return filename;
+}
+
+#else
+
+void RNA_api_image(StructRNA *srna)
+{
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ func= RNA_def_function(srna, "get_export_path", "rna_Image_get_export_path");
+ RNA_def_function_ui_description(func, "Produce image export path.");
+ parm= RNA_def_string(func, "dest_dir", "", 0, "", "Destination directory.");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm= RNA_def_boolean(func, "get_rel_path", 1, "", "Return relative path if True.");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm= RNA_def_string(func, "path", "", 0, "", "Absolute export path.");
+ RNA_def_function_return(func, parm);
+
+ func= RNA_def_function(srna, "get_abs_filename", "rna_Image_get_abs_filename");
+ RNA_def_function_ui_description(func, "Get absolute filename.");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ parm= RNA_def_string_file_path(func, "abs_filename", NULL, 0, "", "Image/movie absolute filename.");
+ RNA_def_function_return(func, parm);
+}
+
+#endif
+
diff --git a/source/blender/makesrna/intern/rna_material_api.c b/source/blender/makesrna/intern/rna_material_api.c
new file mode 100644
index 00000000000..aa28b6b923c
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_material_api.c
@@ -0,0 +1,126 @@
+/**
+ *
+ *
+ * ***** 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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "RNA_define.h"
+#include "RNA_types.h"
+
+#include "DNA_material_types.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_material.h"
+#include "BKE_texture.h"
+
+/*
+ Adds material to the first free texture slot.
+ If all slots are busy, replaces the first.
+*/
+static void rna_Material_add_texture(Material *ma, Tex *tex, int mapto, int texco)
+{
+ int i;
+ MTex *mtex;
+ int slot= -1;
+
+ for (i= 0; i < MAX_MTEX; i++) {
+ if (!ma->mtex[i]) {
+ slot= i;
+ break;
+ }
+ }
+
+ if (slot == -1)
+ slot= 0;
+
+ if (ma->mtex[slot]) {
+ ma->mtex[slot]->tex->id.us--;
+ }
+ else {
+ ma->mtex[slot]= add_mtex();
+ }
+
+ mtex= ma->mtex[slot];
+
+ mtex->tex= tex;
+ id_us_plus(&tex->id);
+
+ mtex->texco= mapto;
+ mtex->mapto= texco;
+}
+
+#else
+
+void RNA_api_material(StructRNA *srna)
+{
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ /* copied from rna_def_material_mtex (rna_material.c) */
+ static EnumPropertyItem prop_texture_coordinates_items[] = {
+ {TEXCO_GLOB, "GLOBAL", 0, "Global", "Uses global coordinates for the texture coordinates."},
+ {TEXCO_OBJECT, "OBJECT", 0, "Object", "Uses linked object's coordinates for texture coordinates."},
+ {TEXCO_UV, "UV", 0, "UV", "Uses UV coordinates for texture coordinates."},
+ {TEXCO_ORCO, "ORCO", 0, "Generated", "Uses the original undeformed coordinates of the object."},
+ {TEXCO_STRAND, "STRAND", 0, "Strand", "Uses normalized strand texture coordinate (1D)."},
+ {TEXCO_STICKY, "STICKY", 0, "Sticky", "Uses mesh's sticky coordinates for the texture coordinates."},
+ {TEXCO_WINDOW, "WINDOW", 0, "Window", "Uses screen coordinates as texture coordinates."},
+ {TEXCO_NORM, "NORMAL", 0, "Normal", "Uses normal vector as texture coordinates."},
+ {TEXCO_REFL, "REFLECTION", 0, "Reflection", "Uses reflection vector as texture coordinates."},
+ {TEXCO_STRESS, "STRESS", 0, "Stress", "Uses the difference of edge lengths compared to original coordinates of the mesh."},
+ {TEXCO_TANGENT, "TANGENT", 0, "Tangent", "Uses the optional tangent vector as texture coordinates."},
+
+ {0, NULL, 0, NULL, NULL}};
+
+ static EnumPropertyItem prop_texture_mapto_items[] = {
+ {MAP_COL, "COLOR", 0, "Color", "Causes the texture to affect basic color of the material"},
+ {MAP_NORM, "NORMAL", 0, "Normal", "Causes the texture to affect the rendered normal"},
+ {MAP_COLSPEC, "SPECULAR_COLOR", 0, "Specularity Color", "Causes the texture to affect the specularity color"},
+ {MAP_COLMIR, "MIRROR", 0, "Mirror", "Causes the texture to affect the mirror color"},
+ {MAP_REF, "REFLECTION", 0, "Reflection", "Causes the texture to affect the value of the materials reflectivity"},
+ {MAP_SPEC, "SPECULARITY", 0, "Specularity", "Causes the texture to affect the value of specularity"},
+ {MAP_EMIT, "EMIT", 0, "Emit", "Causes the texture to affect the emit value"},
+ {MAP_ALPHA, "ALPHA", 0, "Alpha", "Causes the texture to affect the alpha value"},
+ {MAP_HAR, "HARDNESS", 0, "Hardness", "Causes the texture to affect the hardness value"},
+ {MAP_RAYMIRR, "RAY_MIRROR", 0, "Ray-Mirror", "Causes the texture to affect the ray-mirror value"},
+ {MAP_TRANSLU, "TRANSLUCENCY", 0, "Translucency", "Causes the texture to affect the translucency value"},
+ {MAP_AMB, "AMBIENT", 0, "Ambient", "Causes the texture to affect the value of ambient"},
+ {MAP_DISPLACE, "DISPLACEMENT", 0, "Displacement", "Let the texture displace the surface"},
+ {MAP_WARP, "WARP", 0, "Warp", "Let the texture warp texture coordinates of next channels"},
+ {0, NULL, 0, NULL, NULL}};
+
+ func= RNA_def_function(srna, "add_texture", "rna_Material_add_texture");
+ RNA_def_function_ui_description(func, "Add a texture to material's free texture slot.");
+ parm= RNA_def_pointer(func, "texture", "Texture", "", "Texture to add.");
+ parm= RNA_def_enum(func, "texture_coordinates", prop_texture_coordinates_items, TEXCO_UV, "", "Source of texture coordinate information."); /* optional */
+ parm= RNA_def_enum(func, "map_to", prop_texture_mapto_items, MAP_COL, "", "Controls which material property the texture affects."); /* optional */
+}
+
+#endif
+
diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c
new file mode 100644
index 00000000000..c6791405109
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_pose_api.c
@@ -0,0 +1,56 @@
+/**
+ * $Id: rna_pose_api.c 23425 2009-09-22 19:09:04Z gsrb3d $
+ *
+ * ***** 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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "RNA_define.h"
+#include "RNA_types.h"
+
+#include "DNA_object_types.h"
+
+/* #include "BLO_sys_types.h" */
+
+#ifdef RNA_RUNTIME
+
+/* #include "DNA_anim_types.h" */
+#include "DNA_action_types.h" /* bPose */
+
+#else
+
+void RNA_api_pose(StructRNA *srna)
+{
+ /* FunctionRNA *func; */
+ /* PropertyRNA *parm; */
+
+}
+
+#endif
+
diff --git a/source/gameengine/Converter/BL_ArmatureActuator.cpp b/source/gameengine/Converter/BL_ArmatureActuator.cpp
new file mode 100644
index 00000000000..4105eb57d5f
--- /dev/null
+++ b/source/gameengine/Converter/BL_ArmatureActuator.cpp
@@ -0,0 +1,267 @@
+/**
+ * $Id: BL_ArmatureActuator.cpp 23562 2009-09-29 21:42:40Z campbellbarton $
+ *
+ * ***** 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 *****
+ */
+
+#include "DNA_action_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_actuator_types.h"
+#include "BKE_constraint.h"
+#include "BLI_arithb.h"
+#include "BL_ArmatureActuator.h"
+#include "BL_ArmatureObject.h"
+
+/**
+ * This class is the conversion of the Pose channel constraint.
+ * It makes a link between the pose constraint and the KX scene.
+ * The main purpose is to give access to the constraint target
+ * to link it to a game object.
+ * It also allows to activate/deactivate constraints during the game.
+ * Later it will also be possible to create constraint on the fly
+ */
+
+BL_ArmatureActuator::BL_ArmatureActuator(SCA_IObject* obj,
+ int type,
+ const char *posechannel,
+ const char *constraintname,
+ KX_GameObject* targetobj,
+ KX_GameObject* subtargetobj,
+ float weight) :
+ SCA_IActuator(obj, KX_ACT_ARMATURE),
+ m_constraint(NULL),
+ m_gametarget(targetobj),
+ m_gamesubtarget(subtargetobj),
+ m_posechannel(posechannel),
+ m_constraintname(constraintname),
+ m_weight(weight),
+ m_type(type)
+{
+ if (m_gametarget)
+ m_gametarget->RegisterActuator(this);
+ if (m_gamesubtarget)
+ m_gamesubtarget->RegisterActuator(this);
+ FindConstraint();
+}
+
+BL_ArmatureActuator::~BL_ArmatureActuator()
+{
+ if (m_gametarget)
+ m_gametarget->UnregisterActuator(this);
+ if (m_gamesubtarget)
+ m_gamesubtarget->UnregisterActuator(this);
+}
+
+void BL_ArmatureActuator::ProcessReplica()
+{
+ // the replica is tracking the same object => register it (this may be changed in Relnk())
+ if (m_gametarget)
+ m_gametarget->RegisterActuator(this);
+ if (m_gamesubtarget)
+ m_gamesubtarget->UnregisterActuator(this);
+ SCA_IActuator::ProcessReplica();
+}
+
+void BL_ArmatureActuator::ReParent(SCA_IObject* parent)
+{
+ SCA_IActuator::ReParent(parent);
+ // must remap the constraint
+ FindConstraint();
+}
+
+bool BL_ArmatureActuator::UnlinkObject(SCA_IObject* clientobj)
+{
+ bool res=false;
+ if (clientobj == m_gametarget)
+ {
+ // this object is being deleted, we cannot continue to track it.
+ m_gametarget = NULL;
+ res = true;
+ }
+ if (clientobj == m_gamesubtarget)
+ {
+ // this object is being deleted, we cannot continue to track it.
+ m_gamesubtarget = NULL;
+ res = true;
+ }
+ return res;
+}
+
+void BL_ArmatureActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
+{
+ void **h_obj = (*obj_map)[m_gametarget];
+ if (h_obj) {
+ if (m_gametarget)
+ m_gametarget->UnregisterActuator(this);
+ m_gametarget = (KX_GameObject*)(*h_obj);
+ m_gametarget->RegisterActuator(this);
+ }
+ h_obj = (*obj_map)[m_gamesubtarget];
+ if (h_obj) {
+ if (m_gamesubtarget)
+ m_gamesubtarget->UnregisterActuator(this);
+ m_gamesubtarget = (KX_GameObject*)(*h_obj);
+ m_gamesubtarget->RegisterActuator(this);
+ }
+}
+
+void BL_ArmatureActuator::FindConstraint()
+{
+ m_constraint = NULL;
+
+ if (m_gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) {
+ BL_ArmatureObject* armobj = (BL_ArmatureObject*)m_gameobj;
+ m_constraint = armobj->GetConstraint(m_posechannel, m_constraintname);
+ }
+}
+
+bool BL_ArmatureActuator::Update(double curtime, bool frame)
+{
+ // the only role of this actuator is to ensure that the armature pose will be evaluated
+ bool result = false;
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+ if (!bNegativeEvent) {
+ BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent();
+ switch (m_type) {
+ case ACT_ARM_RUN:
+ result = true;
+ obj->SetActiveAction(NULL, 0, curtime);
+ break;
+ case ACT_ARM_ENABLE:
+ if (m_constraint)
+ m_constraint->ClrConstraintFlag(CONSTRAINT_OFF);
+ break;
+ case ACT_ARM_DISABLE:
+ if (m_constraint)
+ m_constraint->SetConstraintFlag(CONSTRAINT_OFF);
+ break;
+ case ACT_ARM_SETTARGET:
+ if (m_constraint) {
+ m_constraint->SetTarget(m_gametarget);
+ m_constraint->SetSubtarget(m_gamesubtarget);
+ }
+ break;
+ case ACT_ARM_SETWEIGHT:
+ if (m_constraint)
+ m_constraint->SetWeight(m_weight);
+ break;
+ }
+ }
+ return result;
+}
+
+#ifndef DISABLE_PYTHON
+
+/* ------------------------------------------------------------------------- */
+/* Python Integration Hooks */
+/* ------------------------------------------------------------------------- */
+
+PyTypeObject BL_ArmatureActuator::Type = {
+#if (PY_VERSION_HEX >= 0x02060000)
+ PyVarObject_HEAD_INIT(NULL, 0)
+#else
+ /* python 2.5 and below */
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+#endif
+ "BL_ArmatureActuator",
+ sizeof(PyObjectPlus_Proxy),
+ 0,
+ py_base_dealloc,
+ 0,
+ 0,
+ 0,
+ 0,
+ py_base_repr,
+ 0,0,0,0,0,0,0,0,0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ 0,0,0,0,0,0,0,
+ Methods,
+ 0,
+ 0,
+ &SCA_IActuator::Type,
+ 0,0,0,0,0,0,
+ py_base_new
+};
+
+
+PyMethodDef BL_ArmatureActuator::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+PyAttributeDef BL_ArmatureActuator::Attributes[] = {
+ KX_PYATTRIBUTE_RO_FUNCTION("constraint", BL_ArmatureActuator, pyattr_get_constraint),
+ KX_PYATTRIBUTE_RW_FUNCTION("target", BL_ArmatureActuator, pyattr_get_object, pyattr_set_object),
+ KX_PYATTRIBUTE_RW_FUNCTION("subtarget", BL_ArmatureActuator, pyattr_get_object, pyattr_set_object),
+ KX_PYATTRIBUTE_FLOAT_RW("weight",0.0f,1.0f,BL_ArmatureActuator,m_weight),
+ KX_PYATTRIBUTE_INT_RW("type",0,ACT_ARM_MAXTYPE,false,BL_ArmatureActuator,m_type),
+ { NULL } //Sentinel
+};
+
+PyObject* BL_ArmatureActuator::pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ BL_ArmatureActuator* actuator = static_cast<BL_ArmatureActuator*>(self);
+ KX_GameObject *target = (!strcmp(attrdef->m_name, "target")) ? actuator->m_gametarget : actuator->m_gamesubtarget;
+ if (!target)
+ Py_RETURN_NONE;
+ else
+ return target->GetProxy();
+}
+
+int BL_ArmatureActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ BL_ArmatureActuator* actuator = static_cast<BL_ArmatureActuator*>(self);
+ KX_GameObject* &target = (!strcmp(attrdef->m_name, "target")) ? actuator->m_gametarget : actuator->m_gamesubtarget;
+ KX_GameObject *gameobj;
+
+ if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: BL_ArmatureActuator"))
+ return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
+
+ if (target != NULL)
+ target->UnregisterActuator(actuator);
+
+ target = gameobj;
+
+ if (target)
+ target->RegisterActuator(actuator);
+
+ return PY_SET_ATTR_SUCCESS;
+}
+
+PyObject* BL_ArmatureActuator::pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ BL_ArmatureActuator* actuator = static_cast<BL_ArmatureActuator*>(self);
+ BL_ArmatureConstraint* constraint = actuator->m_constraint;
+ if (!constraint)
+ Py_RETURN_NONE;
+ else
+ return constraint->GetProxy();
+}
+
+#endif // DISABLE_PYTHON
+
diff --git a/source/gameengine/Converter/BL_ArmatureActuator.h b/source/gameengine/Converter/BL_ArmatureActuator.h
new file mode 100644
index 00000000000..29b07b16d52
--- /dev/null
+++ b/source/gameengine/Converter/BL_ArmatureActuator.h
@@ -0,0 +1,93 @@
+/**
+ * $Id: BL_ArmatureActuator.h 23562 2009-09-29 21:42:40Z campbellbarton $
+ *
+ * ***** 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 *****
+ */
+#ifndef BL_ARMATUREACTUATOR
+#define BL_ARMATUREACTUATOR
+
+#include "SCA_IActuator.h"
+#include "BL_ArmatureConstraint.h"
+
+/**
+ * This class is the conversion of the Pose channel constraint.
+ * It makes a link between the pose constraint and the KX scene.
+ * The main purpose is to give access to the constraint target
+ * to link it to a game object.
+ * It also allows to activate/deactivate constraints during the game.
+ * Later it will also be possible to create constraint on the fly
+ */
+
+class BL_ArmatureActuator : public SCA_IActuator
+{
+ Py_Header;
+public:
+ BL_ArmatureActuator(SCA_IObject* gameobj,
+ int type,
+ const char *posechannel,
+ const char *constraintname,
+ KX_GameObject* targetobj,
+ KX_GameObject* subtargetobj,
+ float weight);
+
+ virtual ~BL_ArmatureActuator();
+
+ virtual CValue* GetReplica() {
+ BL_ArmatureActuator* replica = new BL_ArmatureActuator(*this);
+ replica->ProcessReplica();
+ return replica;
+ };
+ virtual void ProcessReplica();
+ virtual bool UnlinkObject(SCA_IObject* clientobj);
+ virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
+ virtual bool Update(double curtime, bool frame);
+ virtual void ReParent(SCA_IObject* parent);
+
+#ifndef DISABLE_PYTHON
+
+ /* These are used to get and set m_target */
+ static PyObject* pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject* pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+ static int pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+
+#endif // DISABLE_PYTHON
+
+private:
+ // identify the constraint that this actuator controls
+ void FindConstraint();
+
+ BL_ArmatureConstraint* m_constraint;
+ KX_GameObject* m_gametarget;
+ KX_GameObject* m_gamesubtarget;
+ STR_String m_posechannel;
+ STR_String m_constraintname;
+ float m_weight;
+ int m_type;
+};
+
+#endif //BL_ARMATUREACTUATOR
+
+
diff --git a/source/gameengine/Converter/BL_ArmatureChannel.cpp b/source/gameengine/Converter/BL_ArmatureChannel.cpp
new file mode 100644
index 00000000000..817049c6977
--- /dev/null
+++ b/source/gameengine/Converter/BL_ArmatureChannel.cpp
@@ -0,0 +1,469 @@
+/**
+ * $Id: BL_ArmatureChannel.cpp 23562 2009-09-29 21:42:40Z campbellbarton $
+ * ***** 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 *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_armature_types.h"
+#include "BL_ArmatureChannel.h"
+#include "BL_ArmatureObject.h"
+#include "BL_ArmatureConstraint.h"
+#include "BLI_arithb.h"
+#include "BLI_string.h"
+
+#ifndef DISABLE_PYTHON
+
+PyTypeObject BL_ArmatureChannel::Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BL_ArmatureChannel",
+ sizeof(PyObjectPlus_Proxy),
+ 0,
+ py_base_dealloc,
+ 0,
+ 0,
+ 0,
+ 0,
+ py_base_repr,
+ 0,0,0,0,0,0,0,0,0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ 0,0,0,0,0,0,0,
+ Methods,
+ 0,
+ 0,
+ &CValue::Type,
+ 0,0,0,0,0,0,
+ py_base_new
+};
+
+PyObject* BL_ArmatureChannel::py_repr(void)
+{
+ return PyUnicode_FromString(m_posechannel->name);
+}
+
+PyObject *BL_ArmatureChannel::GetProxy()
+{
+ return GetProxyPlus_Ext(this, &Type, m_posechannel);
+}
+
+PyObject *BL_ArmatureChannel::NewProxy(bool py_owns)
+{
+ return NewProxyPlus_Ext(this, &Type, m_posechannel, py_owns);
+}
+
+#endif // DISABLE_PYTHON
+
+BL_ArmatureChannel::BL_ArmatureChannel(
+ BL_ArmatureObject *armature,
+ bPoseChannel *posechannel)
+ : PyObjectPlus(), m_posechannel(posechannel), m_armature(armature)
+{
+}
+
+BL_ArmatureChannel::~BL_ArmatureChannel()
+{
+}
+
+#ifndef DISABLE_PYTHON
+
+// PYTHON
+
+PyMethodDef BL_ArmatureChannel::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+// order of definition of attributes, must match Attributes[] array
+#define BCA_BONE 0
+#define BCA_PARENT 1
+
+PyAttributeDef BL_ArmatureChannel::Attributes[] = {
+ // Keep these attributes in order of BCA_ defines!!! used by py_attr_getattr and py_attr_setattr
+ KX_PYATTRIBUTE_RO_FUNCTION("bone",BL_ArmatureChannel,py_attr_getattr),
+ KX_PYATTRIBUTE_RO_FUNCTION("parent",BL_ArmatureChannel,py_attr_getattr),
+
+ { NULL } //Sentinel
+};
+
+/* attributes directly taken from bPoseChannel */
+PyAttributeDef BL_ArmatureChannel::AttributesPtr[] = {
+ KX_PYATTRIBUTE_CHAR_RO("name",bPoseChannel,name),
+ KX_PYATTRIBUTE_FLAG_RO("has_ik",bPoseChannel,flag, POSE_CHAIN),
+ KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_x",bPoseChannel,ikflag, BONE_IK_NO_XDOF),
+ KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_y",bPoseChannel,ikflag, BONE_IK_NO_YDOF),
+ KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_z",bPoseChannel,ikflag, BONE_IK_NO_ZDOF),
+ KX_PYATTRIBUTE_FLAG_RO("ik_limit_x",bPoseChannel,ikflag, BONE_IK_XLIMIT),
+ KX_PYATTRIBUTE_FLAG_RO("ik_limit_y",bPoseChannel,ikflag, BONE_IK_YLIMIT),
+ KX_PYATTRIBUTE_FLAG_RO("ik_limit_z",bPoseChannel,ikflag, BONE_IK_ZLIMIT),
+ KX_PYATTRIBUTE_FLAG_RO("ik_rot_control",bPoseChannel,ikflag, BONE_IK_ROTCTL),
+ KX_PYATTRIBUTE_FLAG_RO("ik_lin_control",bPoseChannel,ikflag, BONE_IK_LINCTL),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RW("location",-FLT_MAX,FLT_MAX,bPoseChannel,loc,3),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RW("scale",-FLT_MAX,FLT_MAX,bPoseChannel,size,3),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RW("rotation_quaternion",-1.0f,1.0f,bPoseChannel,quat,4),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RW("rotaion_euler",-10.f,10.f,bPoseChannel,eul,3),
+ KX_PYATTRIBUTE_SHORT_RW("rotation_mode",0,ROT_MODE_MAX-1,false,bPoseChannel,rotmode),
+ KX_PYATTRIBUTE_FLOAT_MATRIX_RO("channel_matrix",bPoseChannel,chan_mat,4),
+ KX_PYATTRIBUTE_FLOAT_MATRIX_RO("pose_matrix",bPoseChannel,pose_mat,4),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_head",bPoseChannel,pose_head,3),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_tail",bPoseChannel,pose_tail,3),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_min_x",bPoseChannel,limitmin[0]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_max_x",bPoseChannel,limitmax[0]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_min_y",bPoseChannel,limitmin[1]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_max_y",bPoseChannel,limitmax[1]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_min_z",bPoseChannel,limitmin[2]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_max_z",bPoseChannel,limitmax[2]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_x",bPoseChannel,stiffness[0]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_y",bPoseChannel,stiffness[1]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_z",bPoseChannel,stiffness[2]),
+ KX_PYATTRIBUTE_FLOAT_RO("ik_stretch",bPoseChannel,ikstretch),
+ KX_PYATTRIBUTE_FLOAT_RW("ik_rot_weight",0,1.0f,bPoseChannel,ikrotweight),
+ KX_PYATTRIBUTE_FLOAT_RW("ik_lin_weight",0,1.0f,bPoseChannel,iklinweight),
+ KX_PYATTRIBUTE_RW_FUNCTION("joint_rotation",BL_ArmatureChannel,py_attr_get_joint_rotation,py_attr_set_joint_rotation),
+ { NULL } //Sentinel
+};
+
+PyObject* BL_ArmatureChannel::py_attr_getattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v);
+ bPoseChannel* channel = self->m_posechannel;
+ int attr_order = attrdef-Attributes;
+
+ if (!channel) {
+ PyErr_SetString(PyExc_AttributeError, "channel is NULL");
+ return NULL;
+ }
+
+ switch (attr_order) {
+ case BCA_BONE:
+ // bones are standalone proxy
+ return NewProxyPlus_Ext(NULL,&BL_ArmatureBone::Type,channel->bone,false);
+ case BCA_PARENT:
+ {
+ BL_ArmatureChannel* parent = self->m_armature->GetChannel(channel->parent);
+ if (parent)
+ return parent->GetProxy();
+ else
+ Py_RETURN_NONE;
+ }
+ }
+ PyErr_SetString(PyExc_AttributeError, "channel unknown attribute");
+ return NULL;
+}
+
+int BL_ArmatureChannel::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v);
+ bPoseChannel* channel = self->m_posechannel;
+ int attr_order = attrdef-Attributes;
+
+ int ival;
+ double dval;
+ char* sval;
+ KX_GameObject *oval;
+
+ if (!channel) {
+ PyErr_SetString(PyExc_AttributeError, "channel is NULL");
+ return PY_SET_ATTR_FAIL;
+ }
+
+ switch (attr_order) {
+ default:
+ break;
+ }
+
+ PyErr_SetString(PyExc_AttributeError, "channel unknown attribute");
+ return PY_SET_ATTR_FAIL;
+}
+
+PyObject* BL_ArmatureChannel::py_attr_get_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v);
+ bPoseChannel* pchan = self->m_posechannel;
+ // decompose the pose matrix in euler rotation
+ float rest_mat[3][3];
+ float pose_mat[3][3];
+ float joint_mat[3][3];
+ float joints[3];
+ float norm;
+ double sa, ca;
+ // get rotation in armature space
+ Mat3CpyMat4(pose_mat, pchan->pose_mat);
+ Mat3Ortho(pose_mat);
+ if (pchan->parent) {
+ // bone has a parent, compute the rest pose of the bone taking actual pose of parent
+ Mat3IsMat3MulMat4(rest_mat, pchan->bone->bone_mat, pchan->parent->pose_mat);
+ Mat3Ortho(rest_mat);
+ } else {
+ // otherwise, the bone matrix in armature space is the rest pose
+ Mat3CpyMat4(rest_mat, pchan->bone->arm_mat);
+ }
+ // remove the rest pose to get the joint movement
+ Mat3Transp(rest_mat);
+ Mat3MulMat3(joint_mat, rest_mat, pose_mat);
+ joints[0] = joints[1] = joints[2] = 0.f;
+ // returns a 3 element list that gives corresponding joint
+ int flag = 0;
+ if (!(pchan->ikflag & BONE_IK_NO_XDOF))
+ flag |= 1;
+ if (!(pchan->ikflag & BONE_IK_NO_YDOF))
+ flag |= 2;
+ if (!(pchan->ikflag & BONE_IK_NO_ZDOF))
+ flag |= 4;
+ switch (flag) {
+ case 0: // fixed joint
+ break;
+ case 1: // X only
+ Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ);
+ joints[1] = joints[2] = 0.f;
+ break;
+ case 2: // Y only
+ Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ);
+ joints[0] = joints[2] = 0.f;
+ break;
+ case 3: // X+Y
+ Mat3ToEulO(joint_mat, joints, EULER_ORDER_ZYX);
+ joints[2] = 0.f;
+ break;
+ case 4: // Z only
+ Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ);
+ joints[0] = joints[1] = 0.f;
+ break;
+ case 5: // X+Z
+ // decompose this as an equivalent rotation vector in X/Z plane
+ joints[0] = joint_mat[1][2];
+ joints[2] = -joint_mat[1][0];
+ norm = Normalize(joints);
+ if (norm < FLT_EPSILON) {
+ norm = (joint_mat[1][1] < 0.f) ? M_PI : 0.f;
+ } else {
+ norm = acos(joint_mat[1][1]);
+ }
+ VecMulf(joints, norm);
+ break;
+ case 6: // Y+Z
+ Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ);
+ joints[0] = 0.f;
+ break;
+ case 7: // X+Y+Z
+ // equivalent axis
+ joints[0] = (joint_mat[1][2]-joint_mat[2][1])*0.5f;
+ joints[1] = (joint_mat[2][0]-joint_mat[0][2])*0.5f;
+ joints[2] = (joint_mat[0][1]-joint_mat[1][0])*0.5f;
+ sa = VecLength(joints);
+ ca = (joint_mat[0][0]+joint_mat[1][1]+joint_mat[1][1]-1.0f)*0.5f;
+ if (sa > FLT_EPSILON) {
+ norm = atan2(sa,ca)/sa;
+ } else {
+ if (ca < 0.0) {
+ norm = M_PI;
+ VecMulf(joints,0.f);
+ if (joint_mat[0][0] > 0.f) {
+ joints[0] = 1.0f;
+ } else if (joint_mat[1][1] > 0.f) {
+ joints[1] = 1.0f;
+ } else {
+ joints[2] = 1.0f;
+ }
+ } else {
+ norm = 0.0;
+ }
+ }
+ VecMulf(joints,norm);
+ break;
+ }
+ return newVectorObject(joints, 3, Py_NEW, NULL);
+}
+
+int BL_ArmatureChannel::py_attr_set_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v);
+ bPoseChannel* pchan = self->m_posechannel;
+ PyObject *item;
+ float joints[3];
+ float quat[4];
+
+ if (!PySequence_Check(value) || PySequence_Size(value) != 3) {
+ PyErr_SetString(PyExc_AttributeError, "expected a sequence of [3] floats");
+ return PY_SET_ATTR_FAIL;
+ }
+ for (int i=0; i<3; i++) {
+ item = PySequence_GetItem(value, i); /* new ref */
+ joints[i] = PyFloat_AsDouble(item);
+ Py_DECREF(item);
+ if (joints[i] == -1.0f && PyErr_Occurred()) {
+ PyErr_SetString(PyExc_AttributeError, "expected a sequence of [3] floats");
+ return PY_SET_ATTR_FAIL;
+ }
+ }
+
+ int flag = 0;
+ if (!(pchan->ikflag & BONE_IK_NO_XDOF))
+ flag |= 1;
+ if (!(pchan->ikflag & BONE_IK_NO_YDOF))
+ flag |= 2;
+ if (!(pchan->ikflag & BONE_IK_NO_ZDOF))
+ flag |= 4;
+ QuatOne(quat);
+ switch (flag) {
+ case 0: // fixed joint
+ break;
+ case 1: // X only
+ joints[1] = joints[2] = 0.f;
+ EulOToQuat(joints, EULER_ORDER_XYZ, quat);
+ break;
+ case 2: // Y only
+ joints[0] = joints[2] = 0.f;
+ EulOToQuat(joints, EULER_ORDER_XYZ, quat);
+ break;
+ case 3: // X+Y
+ joints[2] = 0.f;
+ EulOToQuat(joints, EULER_ORDER_ZYX, quat);
+ break;
+ case 4: // Z only
+ joints[0] = joints[1] = 0.f;
+ EulOToQuat(joints, EULER_ORDER_XYZ, quat);
+ break;
+ case 5: // X+Z
+ // X and Z are components of an equivalent rotation axis
+ joints[1] = 0;
+ VecRotToQuat(joints, VecLength(joints), quat);
+ break;
+ case 6: // Y+Z
+ joints[0] = 0.f;
+ EulOToQuat(joints, EULER_ORDER_XYZ, quat);
+ break;
+ case 7: // X+Y+Z
+ // equivalent axis
+ VecRotToQuat(joints, VecLength(joints), quat);
+ break;
+ }
+ if (pchan->rotmode > 0) {
+ QuatToEulO(quat, joints, pchan->rotmode);
+ VecCopyf(pchan->eul, joints);
+ } else
+ QuatCopy(pchan->quat, quat);
+ return PY_SET_ATTR_SUCCESS;
+}
+
+// *************************
+// BL_ArmatureBone
+//
+// Access to Bone structure
+PyTypeObject BL_ArmatureBone::Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BL_ArmatureBone",
+ sizeof(PyObjectPlus_Proxy),
+ 0,
+ py_base_dealloc,
+ 0,
+ 0,
+ 0,
+ 0,
+ py_bone_repr,
+ 0,0,0,0,0,0,0,0,0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ 0,0,0,0,0,0,0,
+ Methods,
+ 0,
+ 0,
+ &CValue::Type,
+ 0,0,0,0,0,0,
+ py_base_new
+};
+
+// not used since this class is never instantiated
+PyObject *BL_ArmatureBone::GetProxy()
+{
+ return NULL;
+}
+PyObject *BL_ArmatureBone::NewProxy(bool py_owns)
+{
+ return NULL;
+}
+
+PyObject *BL_ArmatureBone::py_bone_repr(PyObject *self)
+{
+ Bone* bone = static_cast<Bone*>BGE_PROXY_PTR(self);
+ return PyUnicode_FromString(bone->name);
+}
+
+PyMethodDef BL_ArmatureBone::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+/* no attributes on C++ class since it is never instantiated */
+PyAttributeDef BL_ArmatureBone::Attributes[] = {
+ { NULL } //Sentinel
+};
+
+// attributes that work on proxy ptr (points to a Bone structure)
+PyAttributeDef BL_ArmatureBone::AttributesPtr[] = {
+ KX_PYATTRIBUTE_CHAR_RO("name",Bone,name),
+ KX_PYATTRIBUTE_FLAG_RO("connected",Bone,flag, BONE_CONNECTED),
+ KX_PYATTRIBUTE_FLAG_RO("hinge",Bone,flag, BONE_HINGE),
+ KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("inherit_scale",Bone,flag, BONE_NO_SCALE),
+ KX_PYATTRIBUTE_SHORT_RO("bbone_segments",Bone,segments),
+ KX_PYATTRIBUTE_FLOAT_RO("roll",Bone,roll),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RO("head",Bone,head,3),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RO("tail",Bone,tail,3),
+ KX_PYATTRIBUTE_FLOAT_RO("length",Bone,length),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_head",Bone,arm_head,3),
+ KX_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_tail",Bone,arm_tail,3),
+ KX_PYATTRIBUTE_FLOAT_MATRIX_RO("arm_mat",Bone,arm_mat,4),
+ KX_PYATTRIBUTE_FLOAT_MATRIX_RO("bone_mat",Bone,bone_mat,4),
+ KX_PYATTRIBUTE_RO_FUNCTION("parent",BL_ArmatureBone,py_bone_get_parent),
+ KX_PYATTRIBUTE_RO_FUNCTION("children",BL_ArmatureBone,py_bone_get_parent),
+ { NULL } //Sentinel
+};
+
+PyObject *BL_ArmatureBone::py_bone_get_parent(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ Bone* bone = reinterpret_cast<Bone*>BGE_PROXY_PTR(self);
+ if (bone->parent) {
+ // create a proxy unconnected to any GE object
+ return NewProxyPlus_Ext(NULL,&Type,bone->parent,false);
+ }
+ Py_RETURN_NONE;
+}
+
+PyObject *BL_ArmatureBone::py_bone_get_children(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ Bone* bone = reinterpret_cast<Bone*>BGE_PROXY_PTR(self);
+ Bone* child;
+ int count = 0;
+ for (child=(Bone*)bone->childbase.first; child; child=(Bone*)child->next)
+ count++;
+
+ PyObject* childrenlist = PyList_New(count);
+
+ for (count = 0, child=(Bone*)bone->childbase.first; child; child=(Bone*)child->next, ++count)
+ PyList_SET_ITEM(childrenlist,count,NewProxyPlus_Ext(NULL,&Type,child,false));
+
+ return childrenlist;
+}
+
+#endif // DISABLE_PYTHON
diff --git a/source/gameengine/Converter/BL_ArmatureChannel.h b/source/gameengine/Converter/BL_ArmatureChannel.h
new file mode 100644
index 00000000000..249fa4c8ac7
--- /dev/null
+++ b/source/gameengine/Converter/BL_ArmatureChannel.h
@@ -0,0 +1,95 @@
+/**
+ * $Id: BL_ArmatureChannel.h 23562 2009-09-29 21:42:40Z campbellbarton $
+ *
+ * ***** 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 *****
+ */
+#ifndef __BL_ARMATURECHANNEL
+#define __BL_ARMATURECHANNEL
+
+#include "DNA_action_types.h"
+#include "GEN_HashedPtr.h"
+#include "GEN_Map.h"
+#include "PyObjectPlus.h"
+
+class SCA_IObject;
+class KX_GameObject;
+class BL_ArmatureObject;
+struct bConstraint;
+struct bPoseChannel;
+struct Object;
+struct bPose;
+
+class BL_ArmatureChannel : public PyObjectPlus
+{
+ // use Py_HeaderPtr since we use generic pointer in proxy
+ Py_HeaderPtr;
+
+private:
+ friend class BL_ArmatureObject;
+ struct bPoseChannel* m_posechannel;
+ BL_ArmatureObject* m_armature;
+
+public:
+ BL_ArmatureChannel(class BL_ArmatureObject *armature,
+ struct bPoseChannel *posechannel);
+ virtual ~BL_ArmatureChannel();
+
+#ifndef DISABLE_PYTHON
+ // Python access
+ virtual PyObject* py_repr(void);
+
+ static PyObject* py_attr_getattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+ static int py_attr_setattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+ static PyObject* py_attr_get_joint_rotation(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+ static int py_attr_set_joint_rotation(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+#endif // DISABLE_PYTHON
+};
+
+/* this is a factory class to access bBone data field in the GE.
+ It's not supposed to be instantiated, we only need it for the Attributes and Method array.
+ The actual proxy object will be manually created using NewProxyPtr */
+class BL_ArmatureBone : public PyObjectPlus
+{
+ // use Py_HeaderPtr since we use generic pointer in proxy
+ Py_HeaderPtr;
+private:
+ // make constructor private to make sure no one tries to instantiate this class
+ BL_ArmatureBone() {}
+ virtual ~BL_ArmatureBone() {}
+
+public:
+
+#ifndef DISABLE_PYTHON
+ static PyObject *py_bone_repr(PyObject *self);
+ static PyObject *py_bone_get_parent(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject *py_bone_get_children(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+#endif
+
+};
+
+
+#endif //__BL_ARMATURECHANNEL
+
diff --git a/source/gameengine/Converter/BL_ArmatureConstraint.cpp b/source/gameengine/Converter/BL_ArmatureConstraint.cpp
new file mode 100644
index 00000000000..4c470b67387
--- /dev/null
+++ b/source/gameengine/Converter/BL_ArmatureConstraint.cpp
@@ -0,0 +1,454 @@
+/**
+ * $Id: BL_ArmatureConstraint.cpp 23562 2009-09-29 21:42:40Z campbellbarton $
+ * ***** 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 *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_constraint_types.h"
+#include "DNA_action_types.h"
+#include "BL_ArmatureConstraint.h"
+#include "BL_ArmatureObject.h"
+#include "BLI_arithb.h"
+#include "BLI_string.h"
+
+#ifndef DISABLE_PYTHON
+
+PyTypeObject BL_ArmatureConstraint::Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BL_ArmatureConstraint",
+ sizeof(PyObjectPlus_Proxy),
+ 0,
+ py_base_dealloc,
+ 0,
+ 0,
+ 0,
+ 0,
+ py_base_repr,
+ 0,0,0,0,0,0,0,0,0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ 0,0,0,0,0,0,0,
+ Methods,
+ 0,
+ 0,
+ &CValue::Type,
+ 0,0,0,0,0,0,
+ py_base_new
+};
+
+PyObject* BL_ArmatureConstraint::py_repr(void)
+{
+ return PyUnicode_FromString(m_name);
+}
+
+#endif // DISABLE_PYTHON
+
+BL_ArmatureConstraint::BL_ArmatureConstraint(
+ BL_ArmatureObject *armature,
+ bPoseChannel *posechannel,
+ bConstraint *constraint,
+ KX_GameObject* target,
+ KX_GameObject* subtarget)
+ : PyObjectPlus(), m_armature(armature), m_constraint(constraint), m_posechannel(posechannel)
+{
+ m_target = target;
+ m_blendtarget = (target) ? target->GetBlenderObject() : NULL;
+ m_subtarget = subtarget;
+ m_blendsubtarget = (subtarget) ? subtarget->GetBlenderObject() : NULL;
+ m_pose = m_subpose = NULL;
+ if (m_blendtarget) {
+ Mat4CpyMat4(m_blendmat, m_blendtarget->obmat);
+ if (m_blendtarget->type == OB_ARMATURE)
+ m_pose = m_blendtarget->pose;
+ }
+ if (m_blendsubtarget) {
+ Mat4CpyMat4(m_blendsubmat, m_blendsubtarget->obmat);
+ if (m_blendsubtarget->type == OB_ARMATURE)
+ m_subpose = m_blendsubtarget->pose;
+ }
+ if (m_target)
+ m_target->RegisterObject(m_armature);
+ if (m_subtarget)
+ m_subtarget->RegisterObject(m_armature);
+ BLI_snprintf(m_name, sizeof(m_name), "%s:%s", m_posechannel->name, m_constraint->name);
+}
+
+BL_ArmatureConstraint::~BL_ArmatureConstraint()
+{
+ if (m_target)
+ m_target->UnregisterObject(m_armature);
+ if (m_subtarget)
+ m_subtarget->UnregisterObject(m_armature);
+}
+
+BL_ArmatureConstraint* BL_ArmatureConstraint::GetReplica() const
+{
+ BL_ArmatureConstraint* replica = new BL_ArmatureConstraint(*this);
+ replica->ProcessReplica();
+ return replica;
+}
+
+void BL_ArmatureConstraint::ReParent(BL_ArmatureObject* armature)
+{
+ m_armature = armature;
+ if (m_target)
+ m_target->RegisterObject(armature);
+ if (m_subtarget)
+ m_subtarget->RegisterObject(armature);
+ // find the corresponding constraint in the new armature object
+ if (m_constraint) {
+ bPose* newpose = armature->GetOrigPose();
+ char* constraint = m_constraint->name;
+ char* posechannel = m_posechannel->name;
+ bPoseChannel* pchan;
+ bConstraint* pcon;
+ m_constraint = NULL;
+ m_posechannel = NULL;
+ // and locate the constraint
+ for (pchan = (bPoseChannel*)newpose->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) {
+ if (!strcmp(pchan->name, posechannel)) {
+ // now locate the constraint
+ for (pcon = (bConstraint*)pchan->constraints.first; pcon; pcon=(bConstraint*)pcon->next) {
+ if (!strcmp(pcon->name, constraint)) {
+ m_constraint = pcon;
+ m_posechannel = pchan;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+void BL_ArmatureConstraint::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
+{
+ void **h_obj = (*obj_map)[m_target];
+ if (h_obj) {
+ m_target->UnregisterObject(m_armature);
+ m_target = (KX_GameObject*)(*h_obj);
+ m_target->RegisterObject(m_armature);
+ }
+ h_obj = (*obj_map)[m_subtarget];
+ if (h_obj) {
+ m_subtarget->UnregisterObject(m_armature);
+ m_subtarget = (KX_GameObject*)(*h_obj);
+ m_subtarget->RegisterObject(m_armature);
+ }
+}
+
+bool BL_ArmatureConstraint::UnlinkObject(SCA_IObject* clientobj)
+{
+ bool res=false;
+ if (clientobj == m_target) {
+ m_target = NULL;
+ res = true;
+ }
+ if (clientobj == m_subtarget) {
+ m_subtarget = NULL;
+ res = true;
+ }
+ return res;
+}
+
+void BL_ArmatureConstraint::UpdateTarget()
+{
+ if (m_constraint && !(m_constraint->flag&CONSTRAINT_OFF) && (!m_blendtarget || m_target)) {
+ if (m_blendtarget) {
+ // external target, must be updated
+ m_target->UpdateBlenderObjectMatrix(m_blendtarget);
+ if (m_pose && m_target->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
+ // update the pose in case a bone is specified in the constraint target
+ m_blendtarget->pose = ((BL_ArmatureObject*)m_target)->GetOrigPose();
+ }
+ if (m_blendsubtarget && m_subtarget) {
+ m_subtarget->UpdateBlenderObjectMatrix(m_blendsubtarget);
+ if (m_subpose && m_subtarget->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
+ m_blendsubtarget->pose = ((BL_ArmatureObject*)m_target)->GetOrigPose();
+ }
+ }
+}
+
+void BL_ArmatureConstraint::RestoreTarget()
+{
+ if (m_constraint && !(m_constraint->flag&CONSTRAINT_OFF) && (!m_blendtarget || m_target)) {
+ if (m_blendtarget) {
+ Mat4CpyMat4(m_blendtarget->obmat, m_blendmat);
+ if (m_pose)
+ m_blendtarget->pose = m_pose;
+ }
+ if (m_blendsubtarget && m_subtarget) {
+ Mat4CpyMat4(m_blendsubtarget->obmat, m_blendsubmat);
+ if (m_subpose)
+ m_blendsubtarget->pose = m_subpose;
+ }
+ }
+}
+
+bool BL_ArmatureConstraint::Match(const char* posechannel, const char* constraint)
+{
+ return (!strcmp(m_posechannel->name, posechannel) && !strcmp(m_constraint->name, constraint));
+}
+
+void BL_ArmatureConstraint::SetTarget(KX_GameObject* target)
+{
+ if (m_blendtarget) {
+ if (target != m_target) {
+ m_target->UnregisterObject(m_armature);
+ m_target = target;
+ if (m_target)
+ m_target->RegisterObject(m_armature);
+ }
+ }
+
+}
+
+void BL_ArmatureConstraint::SetSubtarget(KX_GameObject* subtarget)
+{
+ if (m_blendsubtarget) {
+ if (subtarget != m_subtarget) {
+ m_subtarget->UnregisterObject(m_armature);
+ m_subtarget = subtarget;
+ if (m_subtarget)
+ m_subtarget->RegisterObject(m_armature);
+ }
+ }
+
+}
+
+#ifndef DISABLE_PYTHON
+
+// PYTHON
+
+PyMethodDef BL_ArmatureConstraint::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+// order of definition of attributes, must match Attributes[] array
+#define BCA_TYPE 0
+#define BCA_NAME 1
+#define BCA_ENFORCE 2
+#define BCA_HEADTAIL 3
+#define BCA_LINERROR 4
+#define BCA_ROTERROR 5
+#define BCA_TARGET 6
+#define BCA_SUBTARGET 7
+#define BCA_ACTIVE 8
+#define BCA_IKWEIGHT 9
+#define BCA_IKTYPE 10
+#define BCA_IKFLAG 11
+#define BCA_IKDIST 12
+#define BCA_IKMODE 13
+
+PyAttributeDef BL_ArmatureConstraint::Attributes[] = {
+ // Keep these attributes in order of BCA_ defines!!! used by py_attr_getattr and py_attr_setattr
+ KX_PYATTRIBUTE_RO_FUNCTION("type",BL_ArmatureConstraint,py_attr_getattr),
+ KX_PYATTRIBUTE_RO_FUNCTION("name",BL_ArmatureConstraint,py_attr_getattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("enforce",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("headtail",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+ KX_PYATTRIBUTE_RO_FUNCTION("lin_error",BL_ArmatureConstraint,py_attr_getattr),
+ KX_PYATTRIBUTE_RO_FUNCTION("rot_error",BL_ArmatureConstraint,py_attr_getattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("target",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("subtarget",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("active",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("ik_weight",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+ KX_PYATTRIBUTE_RO_FUNCTION("ik_type",BL_ArmatureConstraint,py_attr_getattr),
+ KX_PYATTRIBUTE_RO_FUNCTION("ik_flag",BL_ArmatureConstraint,py_attr_getattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("ik_dist",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+ KX_PYATTRIBUTE_RW_FUNCTION("ik_mode",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
+
+ { NULL } //Sentinel
+};
+
+
+PyObject* BL_ArmatureConstraint::py_attr_getattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ BL_ArmatureConstraint* self= static_cast<BL_ArmatureConstraint*>(self_v);
+ bConstraint* constraint = self->m_constraint;
+ bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL;
+ int attr_order = attrdef-Attributes;
+
+ if (!constraint) {
+ PyErr_SetString(PyExc_AttributeError, "constraint is NULL");
+ return NULL;
+ }
+
+ switch (attr_order) {
+ case BCA_TYPE:
+ return PyLong_FromLong(constraint->type);
+ case BCA_NAME:
+ return PyUnicode_FromString(constraint->name);
+ case BCA_ENFORCE:
+ return PyFloat_FromDouble(constraint->enforce);
+ case BCA_HEADTAIL:
+ return PyFloat_FromDouble(constraint->headtail);
+ case BCA_LINERROR:
+ return PyFloat_FromDouble(constraint->lin_error);
+ case BCA_ROTERROR:
+ return PyFloat_FromDouble(constraint->rot_error);
+ case BCA_TARGET:
+ if (!self->m_target)
+ Py_RETURN_NONE;
+ else
+ return self->m_target->GetProxy();
+ case BCA_SUBTARGET:
+ if (!self->m_subtarget)
+ Py_RETURN_NONE;
+ else
+ return self->m_subtarget->GetProxy();
+ case BCA_ACTIVE:
+ return PyBool_FromLong(constraint->flag & CONSTRAINT_OFF);
+ case BCA_IKWEIGHT:
+ case BCA_IKTYPE:
+ case BCA_IKFLAG:
+ case BCA_IKDIST:
+ case BCA_IKMODE:
+ if (!ikconstraint) {
+ PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type");
+ return NULL;
+ }
+ switch (attr_order) {
+ case BCA_IKWEIGHT:
+ return PyFloat_FromDouble((ikconstraint)?ikconstraint->weight:0.0);
+ case BCA_IKTYPE:
+ return PyLong_FromLong(ikconstraint->type);
+ case BCA_IKFLAG:
+ return PyLong_FromLong(ikconstraint->flag);
+ case BCA_IKDIST:
+ return PyFloat_FromDouble(ikconstraint->dist);
+ case BCA_IKMODE:
+ return PyLong_FromLong(ikconstraint->mode);
+ }
+ // should not come here
+ break;
+ }
+ PyErr_SetString(PyExc_AttributeError, "constraint unknown attribute");
+ return NULL;
+}
+
+int BL_ArmatureConstraint::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ BL_ArmatureConstraint* self= static_cast<BL_ArmatureConstraint*>(self_v);
+ bConstraint* constraint = self->m_constraint;
+ bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL;
+ int attr_order = attrdef-Attributes;
+ int ival;
+ double dval;
+ char* sval;
+ KX_GameObject *oval;
+
+ if (!constraint) {
+ PyErr_SetString(PyExc_AttributeError, "constraint is NULL");
+ return PY_SET_ATTR_FAIL;
+ }
+
+ switch (attr_order) {
+ case BCA_ENFORCE:
+ dval = PyFloat_AsDouble(value);
+ if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */
+ PyErr_SetString(PyExc_AttributeError, "constraint.enforce = float: BL_ArmatureConstraint, expected a float between 0 and 1");
+ return PY_SET_ATTR_FAIL;
+ }
+ constraint->enforce = dval;
+ return PY_SET_ATTR_SUCCESS;
+
+ case BCA_HEADTAIL:
+ dval = PyFloat_AsDouble(value);
+ if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */
+ PyErr_SetString(PyExc_AttributeError, "constraint.headtail = float: BL_ArmatureConstraint, expected a float between 0 and 1");
+ return PY_SET_ATTR_FAIL;
+ }
+ constraint->headtail = dval;
+ return PY_SET_ATTR_SUCCESS;
+
+ case BCA_TARGET:
+ if (!ConvertPythonToGameObject(value, &oval, true, "constraint.target = value: BL_ArmatureConstraint"))
+ return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
+ self->SetTarget(oval);
+ return PY_SET_ATTR_SUCCESS;
+
+ case BCA_SUBTARGET:
+ if (!ConvertPythonToGameObject(value, &oval, true, "constraint.subtarget = value: BL_ArmatureConstraint"))
+ return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
+ self->SetSubtarget(oval);
+ return PY_SET_ATTR_SUCCESS;
+
+ case BCA_ACTIVE:
+ ival = PyObject_IsTrue( value );
+ if (ival == -1) {
+ PyErr_SetString(PyExc_AttributeError, "constraint.active = bool: BL_ArmatureConstraint, expected True or False");
+ return PY_SET_ATTR_FAIL;
+ }
+ self->m_constraint->flag = (self->m_constraint->flag & ~CONSTRAINT_OFF) | ((ival)?0:CONSTRAINT_OFF);
+ return PY_SET_ATTR_SUCCESS;
+
+ case BCA_IKWEIGHT:
+ case BCA_IKDIST:
+ case BCA_IKMODE:
+ if (!ikconstraint) {
+ PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type");
+ return PY_SET_ATTR_FAIL;
+ }
+ switch (attr_order) {
+ case BCA_IKWEIGHT:
+ dval = PyFloat_AsDouble(value);
+ if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */
+ PyErr_SetString(PyExc_AttributeError, "constraint.weight = float: BL_ArmatureConstraint, expected a float between 0 and 1");
+ return PY_SET_ATTR_FAIL;
+ }
+ ikconstraint->weight = dval;
+ return PY_SET_ATTR_SUCCESS;
+
+ case BCA_IKDIST:
+ dval = PyFloat_AsDouble(value);
+ if (dval < 0.0f) { /* also accounts for non float */
+ PyErr_SetString(PyExc_AttributeError, "constraint.ik_dist = float: BL_ArmatureConstraint, expected a positive float");
+ return PY_SET_ATTR_FAIL;
+ }
+ ikconstraint->dist = dval;
+ return PY_SET_ATTR_SUCCESS;
+
+ case BCA_IKMODE:
+ ival = PyLong_AsLong(value);
+ if (ival < 0) {
+ PyErr_SetString(PyExc_AttributeError, "constraint.ik_mode = integer: BL_ArmatureConstraint, expected a positive integer");
+ return PY_SET_ATTR_FAIL;
+ }
+ ikconstraint->mode = ival;
+ return PY_SET_ATTR_SUCCESS;
+ }
+ // should not come here
+ break;
+
+ }
+
+ PyErr_SetString(PyExc_AttributeError, "constraint unknown attribute");
+ return PY_SET_ATTR_FAIL;
+}
+
+#endif // DISABLE_PYTHON
diff --git a/source/gameengine/Converter/BL_ArmatureConstraint.h b/source/gameengine/Converter/BL_ArmatureConstraint.h
new file mode 100644
index 00000000000..c1510b3c56a
--- /dev/null
+++ b/source/gameengine/Converter/BL_ArmatureConstraint.h
@@ -0,0 +1,118 @@
+/**
+ * $Id: BL_ArmatureConstraint.h 23562 2009-09-29 21:42:40Z campbellbarton $
+ *
+ * ***** 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 *****
+ */
+#ifndef __BL_ARMATURECONSTRAINT
+#define __BL_ARMATURECONSTRAINT
+
+#include "DNA_constraint_types.h"
+#include "GEN_HashedPtr.h"
+#include "GEN_Map.h"
+#include "PyObjectPlus.h"
+
+class SCA_IObject;
+class KX_GameObject;
+class BL_ArmatureObject;
+struct bConstraint;
+struct bPoseChannel;
+struct Object;
+struct bPose;
+
+/**
+ * SG_DList : element of controlled constraint list
+ * head = BL_ArmatureObject::m_controlledConstraints
+ * SG_QList : not used
+ */
+class BL_ArmatureConstraint : public PyObjectPlus
+{
+ Py_Header;
+
+private:
+ struct bConstraint* m_constraint;
+ struct bPoseChannel* m_posechannel;
+ class BL_ArmatureObject* m_armature;
+ char m_name[64];
+ KX_GameObject* m_target;
+ KX_GameObject* m_subtarget;
+ struct Object* m_blendtarget;
+ struct Object* m_blendsubtarget;
+ float m_blendmat[4][4];
+ float m_blendsubmat[4][4];
+ struct bPose* m_pose;
+ struct bPose* m_subpose;
+
+public:
+ BL_ArmatureConstraint(class BL_ArmatureObject *armature,
+ struct bPoseChannel *posechannel,
+ struct bConstraint *constraint,
+ KX_GameObject* target,
+ KX_GameObject* subtarget);
+ virtual ~BL_ArmatureConstraint();
+
+ BL_ArmatureConstraint* GetReplica() const;
+ void ReParent(BL_ArmatureObject* armature);
+ void Relink(GEN_Map<GEN_HashedPtr, void*> *map);
+ bool UnlinkObject(SCA_IObject* clientobj);
+
+ void UpdateTarget();
+ void RestoreTarget();
+
+ bool Match(const char* posechannel, const char* constraint);
+ const char* GetName() { return m_name; }
+
+ void SetConstraintFlag(int flag)
+ {
+ if (m_constraint)
+ m_constraint->flag |= flag;
+ }
+ void ClrConstraintFlag(int flag)
+ {
+ if (m_constraint)
+ m_constraint->flag &= ~flag;
+ }
+ void SetWeight(float weight)
+ {
+ if (m_constraint && m_constraint->type == CONSTRAINT_TYPE_KINEMATIC && m_constraint->data) {
+ bKinematicConstraint* con = (bKinematicConstraint*)m_constraint->data;
+ con->weight = weight;
+ }
+ }
+ void SetTarget(KX_GameObject* target);
+ void SetSubtarget(KX_GameObject* subtarget);
+
+#ifndef DISABLE_PYTHON
+
+ // Python access
+ virtual PyObject* py_repr(void);
+
+ static PyObject* py_attr_getattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+ static int py_attr_setattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+#endif // DISABLE_PYTHON
+};
+
+#endif //__BL_ARMATURECONSTRAINT
+
diff --git a/source/gameengine/GameLogic/SCA_BasicEventManager.cpp b/source/gameengine/GameLogic/SCA_BasicEventManager.cpp
new file mode 100644
index 00000000000..6d81784338e
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_BasicEventManager.cpp
@@ -0,0 +1,61 @@
+/**
+ * Manager for 'always' events. Since always sensors can operate in pulse
+ * mode, they need to be activated.
+ *
+ * $Id: SCA_BasicEventManager.cpp 23490 2009-09-25 16:30:15Z campbellbarton $
+ *
+ * ***** 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 *****
+ */
+
+#include "SCA_BasicEventManager.h"
+#include "SCA_LogicManager.h"
+#include <vector>
+#include "SCA_ISensor.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+using namespace std;
+
+SCA_BasicEventManager::SCA_BasicEventManager(class SCA_LogicManager* logicmgr)
+ : SCA_EventManager(logicmgr, BASIC_EVENTMGR)
+{
+}
+
+SCA_BasicEventManager::~SCA_BasicEventManager()
+{
+}
+
+void SCA_BasicEventManager::NextFrame()
+{
+ SG_DList::iterator<SCA_ISensor> it(m_sensors);
+ for (it.begin();!it.end();++it)
+ {
+ (*it)->Activate(m_logicmgr);
+ }
+}
+
diff --git a/source/gameengine/GameLogic/SCA_BasicEventManager.h b/source/gameengine/GameLogic/SCA_BasicEventManager.h
new file mode 100644
index 00000000000..6b68cfcbe16
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_BasicEventManager.h
@@ -0,0 +1,57 @@
+/**
+ * Manager for sensor that only need to call Update
+ *
+ * $Id: SCA_BasicEventManager.h 23499 2009-09-26 20:03:01Z nexyon $
+ *
+ * ***** 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 *****
+ */
+
+#ifndef __SCA_BASICEVENTMGR
+#define __SCA_BASICEVENTMGR
+
+#include "SCA_EventManager.h"
+#include <vector>
+
+using namespace std;
+
+class SCA_BasicEventManager : public SCA_EventManager
+{
+public:
+ SCA_BasicEventManager(class SCA_LogicManager* logicmgr);
+ ~SCA_BasicEventManager();
+
+ virtual void NextFrame();
+
+
+#ifdef WITH_CXX_GUARDEDALLOC
+public:
+ void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_BasicEventManager"); }
+ void operator delete( void *mem ) { MEM_freeN(mem); }
+#endif
+};
+
+#endif //__SCA_BASICEVENTMGR
+
diff --git a/source/gameengine/Ketsji/KX_ArmatureSensor.cpp b/source/gameengine/Ketsji/KX_ArmatureSensor.cpp
new file mode 100644
index 00000000000..007dc459793
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ArmatureSensor.cpp
@@ -0,0 +1,208 @@
+/**
+ * Armature sensor
+ *
+ * $Id: KX_ArmatureSensor.cpp 23562 2009-09-29 21:42:40Z campbellbarton $
+ *
+ * ***** 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 *****
+ */
+
+#include "DNA_action_types.h"
+#include "DNA_constraint_types.h"
+#include "BKE_constraint.h"
+#include "DNA_sensor_types.h"
+
+#include "BL_ArmatureObject.h"
+#include "KX_ArmatureSensor.h"
+#include "SCA_EventManager.h"
+#include "SCA_LogicManager.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_ArmatureSensor::KX_ArmatureSensor(class SCA_EventManager* eventmgr,
+ SCA_IObject* gameobj,
+ const char *posechannel,
+ const char *constraintname,
+ int type,
+ float value)
+ : SCA_ISensor(gameobj,eventmgr),
+ m_constraint(NULL),
+ m_posechannel(posechannel),
+ m_constraintname(constraintname),
+ m_type(type),
+ m_value(value)
+{
+ FindConstraint();
+}
+
+void KX_ArmatureSensor::Init()
+{
+ m_lastresult = m_invert?true:false;
+ m_result = false;
+ m_reset = true;
+}
+
+void KX_ArmatureSensor::FindConstraint()
+{
+ m_constraint = NULL;
+
+ if (m_gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) {
+ BL_ArmatureObject* armobj = (BL_ArmatureObject*)m_gameobj;
+ // get the persistent pose structure
+ bPose* pose = armobj->GetOrigPose();
+ bPoseChannel* pchan;
+ bConstraint* pcon;
+ // and locate the constraint
+ for (pchan = (bPoseChannel*)pose->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) {
+ if (!strcmp(pchan->name, m_posechannel)) {
+ // now locate the constraint
+ for (pcon = (bConstraint*)pchan->constraints.first; pcon; pcon=(bConstraint*)pcon->next) {
+ if (!strcmp(pcon->name, m_constraintname)) {
+ if (pcon->flag & CONSTRAINT_DISABLE)
+ /* this constraint is not valid, can't use it */
+ break;
+ m_constraint = pcon;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+CValue* KX_ArmatureSensor::GetReplica()
+{
+ KX_ArmatureSensor* replica = new KX_ArmatureSensor(*this);
+ // m_range_expr must be recalculated on replica!
+ replica->ProcessReplica();
+ return replica;
+}
+
+void KX_ArmatureSensor::ReParent(SCA_IObject* parent)
+{
+ SCA_ISensor::ReParent(parent);
+ // must remap the constraint
+ FindConstraint();
+}
+
+bool KX_ArmatureSensor::IsPositiveTrigger()
+{
+ return (m_invert) ? !m_result : m_result;
+}
+
+
+KX_ArmatureSensor::~KX_ArmatureSensor()
+{
+}
+
+bool KX_ArmatureSensor::Evaluate()
+{
+ bool reset = m_reset && m_level;
+
+ m_reset = false;
+ if (!m_constraint)
+ return false;
+ switch (m_type) {
+ case SENS_ARM_STATE_CHANGED:
+ m_result = !(m_constraint->flag & CONSTRAINT_OFF);
+ break;
+ case SENS_ARM_LIN_ERROR_BELOW:
+ m_result = (m_constraint->lin_error < m_value);
+ break;
+ case SENS_ARM_LIN_ERROR_ABOVE:
+ m_result = (m_constraint->lin_error > m_value);
+ break;
+ case SENS_ARM_ROT_ERROR_BELOW:
+ m_result = (m_constraint->rot_error < m_value);
+ break;
+ case SENS_ARM_ROT_ERROR_ABOVE:
+ m_result = (m_constraint->rot_error > m_value);
+ break;
+ }
+ if (m_lastresult!=m_result)
+ {
+ m_lastresult = m_result;
+ return true;
+ }
+ return (reset) ? true : false;
+}
+
+#ifndef DISABLE_PYTHON
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_ArmatureSensor::Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "KX_ArmatureSensor",
+ sizeof(PyObjectPlus_Proxy),
+ 0,
+ py_base_dealloc,
+ 0,
+ 0,
+ 0,
+ 0,
+ py_base_repr,
+ 0,0,0,0,0,0,0,0,0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ 0,0,0,0,0,0,0,
+ Methods,
+ 0,
+ 0,
+ &SCA_ISensor::Type,
+ 0,0,0,0,0,0,
+ py_base_new
+};
+
+PyMethodDef KX_ArmatureSensor::Methods[] = {
+ {NULL,NULL} //Sentinel
+};
+
+PyAttributeDef KX_ArmatureSensor::Attributes[] = {
+ KX_PYATTRIBUTE_RO_FUNCTION("constraint", KX_ArmatureSensor, pyattr_get_constraint),
+ KX_PYATTRIBUTE_FLOAT_RW("value",-FLT_MAX,FLT_MAX,KX_ArmatureSensor,m_value),
+ KX_PYATTRIBUTE_INT_RW("type",0,SENS_ARM_MAXTYPE,false,KX_ArmatureSensor,m_type),
+ { NULL } //Sentinel
+};
+
+PyObject* KX_ArmatureSensor::pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_ArmatureSensor* sensor = static_cast<KX_ArmatureSensor*>(self);
+ if (sensor->m_gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) {
+ BL_ArmatureObject* armobj = (BL_ArmatureObject*)sensor->m_gameobj;
+ BL_ArmatureConstraint* constraint = armobj->GetConstraint(sensor->m_posechannel, sensor->m_constraintname);
+ if (constraint)
+ return constraint->GetProxy();
+ }
+ Py_RETURN_NONE;
+}
+
+#endif // DISABLE_PYTHON
diff --git a/source/gameengine/Ketsji/KX_ArmatureSensor.h b/source/gameengine/Ketsji/KX_ArmatureSensor.h
new file mode 100644
index 00000000000..710fbe1b7bc
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ArmatureSensor.h
@@ -0,0 +1,89 @@
+/**
+ * Property sensor
+ *
+ * $Id: KX_ArmatureSensor.h 23562 2009-09-29 21:42:40Z campbellbarton $
+ *
+ * ***** 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 *****
+ */
+
+#ifndef __KX_ARMATURESENSOR
+#define __KX_ARMATURESENSOR
+
+struct bConstraint;
+
+#include "SCA_ISensor.h"
+#include "DNA_sensor_types.h"
+
+class KX_ArmatureSensor : public SCA_ISensor
+{
+ Py_Header;
+ //class CExpression* m_rightexpr;
+
+protected:
+
+public:
+ KX_ArmatureSensor(class SCA_EventManager* eventmgr,
+ SCA_IObject* gameobj,
+ const char *posechannel,
+ const char *constraintname,
+ int type,
+ float value);
+
+ /**
+ * For property sensor, it is used to release the pre-calculated expression
+ * so that self references are removed before the sensor itself is released
+ */
+ virtual ~KX_ArmatureSensor();
+ virtual CValue* GetReplica();
+ virtual void ReParent(SCA_IObject* parent);
+ virtual void Init();
+ virtual bool Evaluate();
+ virtual bool IsPositiveTrigger();
+
+ // identify the constraint that this actuator controls
+ void FindConstraint();
+
+#ifndef DISABLE_PYTHON
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+ static PyObject* pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef);
+
+#endif // DISABLE_PYTHON
+
+private:
+ struct bConstraint* m_constraint;
+ STR_String m_posechannel;
+ STR_String m_constraintname;
+ int m_type;
+ float m_value;
+ bool m_result;
+ bool m_lastresult;
+};
+
+#endif
+