iDevGames Forums
Pixel editor - Printable Version

+- iDevGames Forums (http://www.idevgames.com/forums)
+-- Forum: Development Zone (/forum-3.html)
+--- Forum: Designer's Studio (/forum-6.html)
+--- Thread: Pixel editor (/thread-6381.html)



Pixel editor - DM6 - Aug 2, 2004 10:03 AM

Anyone seen this? http://www.opensword.org/Pixen/

Open source, and a bunch of features (& companion program for map editing). Maybe some of you who're working on pixel programs will find it helpful.

-Duncan


Pixel editor - skyhawk - Aug 2, 2004 11:02 AM

don't suppose you read THIS on the front page awhile ago Rolleyes

http://www.idevgames.com/The_News/Developer_Reports/New_Pixel_Editor_Coming_to_Mac_OS_X/


Pixel editor - DM6 - Aug 2, 2004 11:09 AM

skyhawk Wrote:don't suppose you read THIS on the front page awhile ago Rolleyes

http://www.idevgames.com/The_News/Developer_Reports/New_Pixel_Editor_Coming_to_Mac_OS_X/

Nope. You sure showed me.

-Duncan


Pixel editor - Marjock - Aug 9, 2004 11:04 PM

did anyone else find this like really laggy? like stuff doesn't refresh at an ice rate when you're dragging it, and sometimes the big red cross hair, targetty thing isn't in the right place and stuff?

Anybody know of a way to magically fix this?

(I'm a 1.25ghz G4 running panther, btw)

-Mark


Pixel editor - skyhawk - Aug 10, 2004 09:25 AM

it works better on 64x64 and smaller images, I believe the problem is they are redrawing the context ALL the time. could be wrong, but I believe that is the problem.

once it irons out a few speed quirks, it is a truly solid app.


Pixel editor - lemniscate - Aug 10, 2004 11:41 AM

Hi, I'm Andy, one of Pixen's developers. I'll try to field these issues:

1. We aren't redrawing the entire context all the time... most of the speed problems are because our data model has some issues. You can see what's being redrawn with Quartz Debug, included in the devtools. But yes, we are refreshing the entire context every pixel a layer is dragged. It really sucks, but because the layers can be translucent, everything has to be redrawn when they're moved. One thing we could do to improve that is keep track of the effective bounds of the layer as the user draws. That is, the bounds in which there's actually data. Right now, each layer has size equivalent to that of the entire image. The current build in SVN is quite a bit faster, but the move tool is still slow.

2. This is another problem that's really been annoying me. The issue is that we use the system-standard mouseMoved event to know when to move the crosshairs. Unfortunately, when a given window isn't specifically focused with, say, a click, that message isn't sent. I just finished fixing one bug with the crosshair - the layers drawer would take focus away from the main window, so the user would have to draw a pixel in the canvas and then undo to use the crosshair again. We're going to try to somehow iron this one out before the next release, but at the moment, I have no idea how. Do any of the programmers around here have any ideas?

Thanks for the kind words, though. I'm sorry that there are still bugs in Pixen, but we're working on 'em!


Pixel editor - codemattic - Aug 11, 2004 02:39 AM

Hi Andy!

I found this on Cocoa-dev - it seems *really* involved just to get mouse moved events even if the view isnt the first responder - but I dont know of another way (if there is Id love to learn it.) Hth!

-Codemattic

PS - thanks for making a neat, free, opensource, cocoa, pixel editor!!

Code:
From: Pandaa <deleted>
Date: April 13, 2004 7:56:18 PM EDT
To: Cocoa Mailing List <deleted>
Subject: Mouse Movement tracking

Hi,
since mouseMoved events is limited to firstResponders and I've often needed mouse movement tracking also when views are not first responder or not even in the main or key window, I put together a simple to use helper class to do pixel accurate mouse moved tracking using tracking rects. It's actually tricky to get precisely right, but here it is - if you wanna know the details, just ask.

Enjoy, hope it's useful to someone.

Usage:
This will track mouse movements with pixel accuracy inside the bounds of a view with no lag:

- (void)awakeFromNib
{
    mainTrackingRectTag = [self addTrackingRect:_bounds owner:self userData:nil assumeInside:NO];
    helper = [[OCMouseMovedHelper alloc] initWithView:self];
}
- (void)mouseEntered:(NSEvent*)theEvent
{
    int track = [theEvent trackingNumber];
    if ( track == mainTrackingRectTag )
    {
    [helper addTrackingRectsForDetectingMovement];
    }
    else if ( [helper mouseEnteredIsMouseMovement:track] )
    {
    NSPoint mouse = [helper addTrackingRectsForDetectingMovement];
    // aha, the mouse moved, do something
    }
}
- (void)mouseExited:(NSEvent*)theEvent
{
    int track = [theEvent trackingNumber];
    if ( track == mainTrackingRectTag )
    [helper removeTrackingRects]; // mouse outside our area of interest
    else if ( [helper mouseExitedIsMouseMovement:track] )
    {
    NSPoint mouse = [helper addTrackingRectsForDetectingMovement];
    // aha, the mouse moved, do something
    }
}

If anyone has suggestions on how to improve this or if there are even better and simpler ways of doing this it would be nice to hear.

.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
.  .  .  . earth water fire air software  - the five elements .  .  .  .
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
// OCMouseMovedHelper.h

#import <Foundation/Foundation.h>

typedef int(*ViewAddTrackingRect)(id,SEL,NSRect,id,void*,BOOL);
typedef void(*ViewRemoveTrackingRect)(id,SEL,int);
typedef NSPoint(*WindowConvertScreenToBase)(id,SEL,NSPoint);
typedef NSPoint(*ViewConvertPointFromView)(id,SEL,NSPoint,NSView*);

@interface OCMouseMovedHelper : NSObject
{
    NSView *view;
    NSWindow *window;
    ViewAddTrackingRect addImplementation;
    ViewRemoveTrackingRect removeImplementation;
    WindowConvertScreenToBase screenToBaseImplementation;
    ViewConvertPointFromView convertPointImplementation;
    void(*trackFromPointImplementation)(id,SEL,NSPoint);
    int tag[6];
}
- (id)initWithView:(NSView*)parentView; // will not retain view

- (BOOL)mouseEnteredIsMouseMovement:(int)trackingNumber;
- (BOOL)mouseExitedIsMouseMovement:(int)trackingNumber;
- (NSPoint)addTrackingRectsForDetectingMovement; // returns [NSEvent mouseLocation] in local coordinates
- (void)addTrackingRectsForDetectingMovementFromPoint:(NSPoint)localMouse;
- (void)removeTrackingRects;
@end

// ---

// OCMouseMovedHelper.m

#import "OCMouseMovedHelper.h"

@implementation OCMouseMovedHelper
- (id)initWithView:(NSView*)parentView
{
    if ( self = [super init] )
    {
    view = parentView;
    addImplementation = (ViewAddTrackingRect)[view methodForSelector:@selector(addTrackingRect:owner:userData:assumeInside:)];
    removeImplementation = (ViewRemoveTrackingRect)[view methodForSelector:@selector(removeTrackingRect:)];
    convertPointImplementation = (ViewConvertPointFromView)[view methodForSelector:@selector(convertPoint:fromView:)];
    window = [parentView window];
    screenToBaseImplementation = (WindowConvertScreenToBase)[window methodForSelector:@selector(convertScreenToBase:)];
    trackFromPointImplementation = (void(*)(id,SEL,NSPoint))[self methodForSelector:@selector(addTrackingRectsForDetectingMovementFromPoint:)];
    int i = 0;
    for ( ; i < 6 ; ++i )
        tag[i] = 0;
    }
    return self;
}
- (void)dealloc
{
    [self removeTrackingRects];
    [super dealloc];
}
- (BOOL)mouseEnteredIsMouseMovement:(int)trackingNumber
{
    return ( (trackingNumber == tag[1]) || (trackingNumber == tag[2]) );
}
- (BOOL)mouseExitedIsMouseMovement:(int)trackingNumber
{
    return ( (trackingNumber == tag[0]) || (trackingNumber == tag[3]) || (trackingNumber == tag[4]) || (trackingNumber == tag[5]) );
}
- (NSPoint)addTrackingRectsForDetectingMovement
{
    NSPoint mouse = [NSEvent mouseLocation];
    mouse = screenToBaseImplementation(window,@selector(convertScreenToBase:),mouse);
    mouse = convertPointImplementation(view,@selector(convertPoint:fromView:),mouse,nil);
    trackFromPointImplementation(self,@selector(addTrackingRectsForDetectingMov​ementFromPoint:),mouse);
    return mouse;
}
- (void)addTrackingRectsForDetectingMovementFromPoint:(NSPoint)localMouse
{
    int xi = (int)(localMouse.x+0.5), yi = (int)(localMouse.y+0.5);
    NSRect clipRect;
    clipRect.origin.x = xi-5; clipRect.origin.y = yi-5;
    clipRect.size.width = 11; clipRect.size.height = 11;
    if ( tag[5] )
    removeImplementation(view,@selector(removeTrackingRect:),tag[5]);
    tag[5] = addImplementation(view,@selector(addTrackingRect:owner:userData:assumeInside:),c​lipRect,view,nil,YES);

    clipRect.origin.x = xi-3; clipRect.origin.y = yi-3;
    clipRect.size.width = 7; clipRect.size.height = 7;
    if ( tag[4] )
    removeImplementation(view,@selector(removeTrackingRect:),tag[4]);
    tag[4] = addImplementation(view,@selector(addTrackingRect:owner:userData:assumeInside:),c​lipRect,view,nil,YES);

    clipRect.origin.x = xi-1; clipRect.origin.y = yi-1;
    clipRect.size.width = 3; clipRect.size.height = 3;
    if ( tag[3] )
    removeImplementation(view,@selector(removeTrackingRect:),tag[3]);
    tag[3] = addImplementation(view,@selector(addTrackingRect:owner:userData:assumeInside:),c​lipRect,view,nil,YES);

    NSRect pixelRect;
    pixelRect.origin.x = xi-0.01; pixelRect.origin.y = yi-0.01;
    pixelRect.size.width = 0.999; pixelRect.size.height = 0.999;
    if ( tag[0] )
    removeImplementation(view,@selector(removeTrackingRect:),tag[0]);
    tag[0] = addImplementation(view,@selector(addTrackingRect:owner:userData:assumeInside:),p​ixelRect,view,nil,YES);

    pixelRect.origin.x = (int)(clipRect.origin.x + 0.5); pixelRect.origin.y = clipRect.origin.y;
    pixelRect.size.width = xi - (int)(clipRect.origin.x + 0.5);
    pixelRect.size.height = clipRect.size.height;
    if ( tag[1] )
    removeImplementation(view,@selector(removeTrackingRect:),tag[1]);
    tag[1] = addImplementation(view,@selector(addTrackingRect:owner:userData:assumeInside:),p​ixelRect,view,nil,NO);

    pixelRect.origin.x = localMouse.x; pixelRect.origin.y = (int)(localMouse.y + 1.5) - 0.01;
    pixelRect.size.width = clipRect.origin.x+clipRect.size.width-localMouse.x;
    pixelRect.size.height = (int)(clipRect.origin.y+clipRect.size.height+0.5)-(int)(localMouse.y + 1.5);
    if ( tag[2] )
    removeImplementation(view,@selector(removeTrackingRect:),tag[2]);
    tag[2] = addImplementation(view,@selector(addTrackingRect:owner:userData:assumeInside:),p​ixelRect,view,nil,NO);
}
- (void)removeTrackingRects
{
    int i = 0;
    for ( ; i < 6 ; ++i )
    if ( tag[i] != 0 )
    {
        removeImplementation(view,@selector(removeTrackingRectangle:),tag[i]);
        tag[i] = 0;
    }
}
@end

(I edited this post to remove some emails that shouldnt of been there)


Pixel editor - codemattic - Aug 11, 2004 08:57 AM

ok - another idea. Make all your windows - including utility windows - setAcceptsMouseMovedEvents:YES. Then in your NSDocument subclass (and possibly in your view) have a -myMouseMoved:(NSEvent *)anEvent. Then subclass NSApplication. In your NSApplication subclass:
Code:
- (void)sendEvent:(NSEvent *)anEvent {
    if ([anEvent type] == NSMouseMoved) {
        [[[NSDocumentController sharedDocumentController] currentDocument] myMouseMoved:anEvent];
    }
    [super sendEvent:anEvent];
}
So even if a utility window becomes key (if the user clicks on the title bar for instance) your document will still get the myMouseMoved: messages (I renamed it myMouseMoved so that you wont respond twice if you just used the mouseMoved:)

A question is should a document update even if its not the current document. If you want this behavior then you need to get the list of documents and send the myMouseMoved: message to all of them.

Obviously your NSDocument subclass then needs to pass the myMouseMoved: message to its views.

Make sense?


Pixel editor - lemniscate - Aug 13, 2004 08:32 PM

Thanks!

Yeah, we were thinking about going the overriding sendEvent route. It's really, really icky, but it'll work. Thanks for the help.