Question

I am coding a modal layer in cocos2d and I would like to use the OpenGL glScissor API call to crop the inside of a CCScrollLayer that I am using,

Basically,

  1. Present some kind of Modal sprite
  2. Put CCScrollLayer with assets on the modal sprite
  3. I want to crop the CCScrollLayer so that it does not overflow the sprite.

Seems pretty simple.

The problem I'm having is that the visit function never seems to be get hit and thus glScissor never gets implemented.

I'm not sure what I'm doing wrong.

The way I do modals is I use blocks to handle a Yes and No condition/state.

// This appears in my "Pick City scene"
-(id) init
{

    if ((self = [super init])) 
    {
        NSLog(@"City list");

        for (City *cityObj in listOfCities) 
        {
            citySpriteOff = [CCSprite spriteWithSpriteFrameName:@"city.png"];
            citySpriteOn = [CCSprite spriteWithSpriteFrameName:@"city_on.png"];

            int x = [cityObj.x intValue];
            int y = [cityObj.y intValue];

            CCMenuItemSprite *mapMenuItem = [CCMenuItemSprite itemFromNormalSprite:citySpriteOff selectedSprite:citySpriteOn target:self selector:@selector(btnCity:)];
            [mapMenuItem setTag:i];
            [mapMenuItem setIsRelativeAnchorPoint:YES];
            [mapMenuItem setAnchorPoint:CGPointMake(0, 0)];
            [mapMenuItem setPosition:CGPointMake(x, y)];
            [mapMenuItem setIsEnabled:YES];

            [mapMenu addChild:mapMenuItem];
            i++;
        } // next

        [self addChild:mapMenu z:2];
    }
}


-(void) btnCity:(id)sender
{
    NSLog(@"clicked a city button");
    int tag = [sender tag];

    City *cityObj = [listOfCities objectAtIndex:tag];
    NSLog(@"You clicked on city: %@", cityObj.name);

    [self lockLayers];

    CCLayer *layer = [CCLayer node];
    [self addChild:layer z:100];

    [MapModalLayer ConfirmCity:cityObj onLayer:layer yesBlock:^{[self btnConfirmedCity:cityObj];} noBlock:^{[self unlockLayers];}];

}



-(void) btnConfirmedCity:(City *)cityObj
{
    NSLog(@"confirmed city: %@", cityObj.name);
}




#pragma mark - Lock/Unlock layers

-(void) lockLayers
{
    [self MenuStatus:NO Node:self];   
}

-(void) unlockLayers
{
    [self MenuStatus:YES Node:self];
}


// Disabled/Enable layers
-(void) MenuStatus:(BOOL)_enable Node:(id)_node
{
    for (id result in ((CCNode *)_node).children) {
        if ([result isKindOfClass:[CCMenu class]]) {
            for (id result1 in ((CCMenu *)result).children) {
                if ([result1 isKindOfClass:[CCMenuItem class]]) {
                    ((CCMenuItem *)result1).isEnabled = _enable;
                }
            }
        }
        else
            [self MenuStatus:_enable Node:result];
    } // next
}

The actual modal code appears here,

@implementation MapModalLayer

- (id)init {
    self = [super init];
    if (self) {
        // This method never seems to be called
        NSLog(@"MapModalLayer init");
    }
    return self;
}

// This method never seems to be called
- (void) visit {
    NSLog(@"Visit");
    if (!self.visible)
        return;

    glPushMatrix(); 
    glEnable(GL_SCISSOR_TEST);  
    glScissor(50, 50, 100 , 150);

    [super visit];

    glDisable(GL_SCISSOR_TEST);
    glPopMatrix();
}


+ (void) CloseAlert: (CCSprite*) alertDialog onCoverLayer: (CCLayer*) coverLayer executingBlock: (void(^)())block {
    // shrink dialog box
    [alertDialog runAction:[CCScaleTo actionWithDuration:kAnimationTime scale:0]];


    // in parallel, fadeout and remove cover layer and execute block 
    // (note: you can't use CCFadeOut since we don't start at opacity 1!)
    [coverLayer runAction:[CCSequence actions:
                           [CCFadeTo actionWithDuration:0.2f opacity:0], 
                           [CCCallBlock actionWithBlock:^{
                                [coverLayer removeFromParentAndCleanup:YES];
                                if (block) block();
                            }],
                           nil]];
}


+(void) ConfirmCity:(City *)cityObj onLayer:(CCLayer *)layer yesBlock :(void (^)())yesBlock noBlock:(void (^)())noBlock
{

    CCLayerColor *coverLayer = [CoverLayer new];
    [layer addChild:coverLayer z:INT_MAX]; // put to the very top to block application touches
    [coverLayer runAction:[CCFadeTo actionWithDuration:kAnimationTime opacity:80]]; // smooth fade-in to dim with semi-transparency

    CGSize winSize = [[CCDirector sharedDirector] winSize];

    CCSprite *dialog = [CCSprite spriteWithSpriteFrameName:@"modal.png"];
    [dialog setPosition:CGPointMake(winSize.width/2,winSize.height/2)];
    [dialog setTag:kDialogTag]; 

    //
    // We put our CCScrollLayer *scroller  content here... it doesn't matter what it is right now
    //

    //
    // Finally we put our accept/reject buttons
    //

    // Tick/Cross buttons    
    CCSprite *closeButtonOn = [CCSprite spriteWithSpriteFrameName:@"btn_close.png"];
    CCSprite *tickButtonOn  = [CCSprite spriteWithSpriteFrameName:@"btn_accept.png"];



    // add one or two buttons, as needed 
    CCMenuItemSprite *opt1Button = [CCMenuItemSprite itemFromNormalSprite:closeButtonOn
                                                           selectedSprite:nil
                                                                    block:^(id sender){ 
                                                                        // close alert and call opt1block when first button is pressed
                                                                        [self CloseAlert:dialog onCoverLayer: coverLayer executingBlock:noBlock];
                                                                    } ];

    [opt1Button setPosition:CGPointMake(-200, -120)];

    // create second button, if requested
    CCMenuItemSprite *opt2Button = [CCMenuItemSprite itemFromNormalSprite:tickButtonOn
                                             selectedSprite:nil
                                                      block:^(id sender){ 
                                                          // close alert and call opt2block when second button is pressed
                                                          [self CloseAlert:dialog onCoverLayer: coverLayer executingBlock:yesBlock];
                                                      } ];



    [opt2Button setPosition:CGPointMake(40, -120)];

    CCMenu *menu = [CCMenu menuWithItems:opt1Button, opt2Button, nil];
    [menu setContentSize:dialog.contentSize];
    [dialog addChild:menu z:2];


    [coverLayer addChild:dialog];

}  


@end

I think its because I only ever use MapModalLayer's private methods only.

But I am not sure.

Is there a way to allow me to use the glScissor in a modal like explained above?

I've tried moving the glScissor code to the display of the modal, but it never seems to do anything.

To confirm it is working, I moved the glScissor code to the parent and it seems to work fine.

Thus, how do I make the modal layer use/work with glScissor?

Was it helpful?

Solution

I have since resolved this problem.

I used the Viewport from http://pastebin.com/tWsEbxvJ

The way I did it was:

  CoverLayer *coverLayer = [CoverLayer new];
    [layer addChild:coverLayer z:INT_MAX]; // put to the very top to block application touches
    [coverLayer runAction:[CCFadeTo actionWithDuration:kAnimationTime opacity:80]]; // smooth fade-in to dim with semi-transparency

    // ------------------------------

    CGSize winSize = [[CCDirector sharedDirector] winSize];

    CCSprite *dialog = [CCSprite spriteWithSpriteFrameName:@"modal.png"];
    [dialog setPosition:CGPointMake(winSize.width/2,winSize.height/2)];
    [dialog setTag:kDialogTag]; 

.. // Build your pagesArray here for ScrollLayer...



    // Now create the scroller and pass-in the pages (set widthOffset to 0 for fullscreen pages)
    CCScrollLayer *scroller = [[CCScrollLayer alloc] initWithLayers:pagesArray widthOffset: 350];
    [scroller setShowPagesIndicator:NO]; 

    // finally add the scroller to your scene
    //[dialog addChild:scroller];


    Viewport *cn = [[Viewport alloc] initWithRect:CGRectMake(3, 0, dialog.contentSize.width-12, dialog.contentSize.height-5)];
    [cn addChild:scroller];

    [scroller release];



    [coverLayer addChild:dialog z:1];

This allows me to put a modal on a layer, put a CCScrollLayer and make sure that the contents do not spill over the internals of the modal sprite I have made (this is why the width configuration looks a bit odd).

Thanks.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top