Exemple #1
0
void Prop2D::onTrack( RemoteHead *rh, Prop2D *parentprop ) {
    if( !tracker ) {
        tracker = new Tracker2D(rh,this);
    }
    tracker->scanProp2D(parentprop);
    tracker->broadcastDiff( false );
    tracker->flipCurrentBuffer();

    // grids
    for(int i=0;i<grid_used_num;i++) {
        Grid *g = grids[i];
        if(!g->tracker) g->tracker = new TrackerGrid(rh,g);
        g->tracker->scanGrid();
        g->tracker->broadcastDiff(this, false );
        g->tracker->flipCurrentBuffer();
    }

    // shader
    if(fragment_shader) {
        ColorReplacerShader *crs = dynamic_cast<ColorReplacerShader*>(fragment_shader);
        if(crs) {
            crs->onTrack(rh);
        }
    }

    // prims
    if( prim_drawer ) {
        prim_drawer->onTrack(this,rh);
    }

    // dynamic image
    if( deck && deck->tex && deck->tex->image ) {
        deck->tex->image->onTrack( deck, rh );        
    }

    // children
    for(int i=0;i<children_num;i++) {
        Prop2D *p = (Prop2D*) children[i];
        p->onTrack( rh, this );
    }
}
Exemple #2
0
Prop2D *createShadow( Vec2 lc ) {
    Prop2D *p = new Prop2D();
    p->setDeck(g_base_deck);
    p->setIndex( B_ATLAS_FLYER_SHADOW );
    p->setScl(PIXEL_PER_CELL,PIXEL_PER_CELL);
    p->setColor( 1,1,1,0.5);
    p->setLoc(lc);
    return p;
}
Exemple #3
0
int main(int argc, char **argv )
{
    bool headless_mode=false;
    for(int i=0;;i++) {
        if(!argv[i])break;
        if(strcmp(argv[i], "--headless") == 0 ) headless_mode = true;
    }

    print("program start");

#ifdef __APPLE__    
    setlocale( LC_ALL, "ja_JP");
#endif
#ifdef WIN32    
    setlocale( LC_ALL, "jpn");
#endif    
    
    // glfw
    if( !glfwInit() ) {
        print("can't init glfw");
        return 1;
    }

    GLFWwindow *window;
    glfwSetErrorCallback( glfw_error_cb );
    window =  glfwCreateWindow( SCRW, SCRH, "min2d", NULL, NULL );
    if(window == NULL ) {
        print("can't open glfw window");
        glfwTerminate();
        return 1;
    }
    glfwMakeContextCurrent(window);    
    glfwSetWindowCloseCallback( window, winclose_callback );
    glfwSetInputMode( window, GLFW_STICKY_KEYS, GL_TRUE );
    glfwSwapInterval(0); // set 1 to use vsync. Use 0 for fast screen capturing and headless
    glfwSetKeyCallback( window, kbdCallback );
#ifdef WIN32
	glewInit();
#endif
    glClearColor(0.2,0.2,0.2,1);

    SoundSystem *ss = new SoundSystem();
    Sound *bgm = ss->newSound( "assets/gymno1short.wav" );
    bgm->play();

    g_keyboard = new Keyboard();
    
    MoyaiClient *moyai_client = new MoyaiClient(window,SCRW,SCRH);
    
    if( headless_mode ) {
        Moyai::globalInitNetwork();
        RemoteHead *rh = new RemoteHead();
        int port = 22222;
        if( rh->startServer(port) == false ) {
            print("headless server: can't start server. port:%d", 22222 );
            exit(1);
        } else {
            print("Start headless server port:%d",port);
        }
        rh->enableSpriteStream();
        rh->enableReprecation(REPRECATOR_SERVER_PORT);
        moyai_client->setRemoteHead(rh);
        rh->setTargetMoyaiClient(moyai_client);
        ss->setRemoteHead(rh);
        rh->setTargetSoundSystem(ss);
        rh->setOnKeyboardCallback(onRemoteKeyboardCallback);
    }

    
    Viewport *viewport = new Viewport();
    int retina = 1;
#if defined(__APPLE__)
    retina = 2;
#endif    
    viewport->setSize(SCRW*retina,SCRH*retina); // set actual framebuffer size to output
    viewport->setScale2D(SCRW,SCRH); // set scale used by props that will be rendered

    float zoom_rate = 1.0f;
    Vec2 center(0,0);
    Camera *camera = new Camera();
    camera->setLoc(0,0);

    Layer *l = new Layer();
    moyai_client->insertLayer(l);
    l->setViewport(viewport);
    l->setCamera(camera);

    Texture *t = new Texture();
    t->load( "./assets/base.png" );
    
    TileDeck *deck = new TileDeck();
    deck->setTexture(t);
    deck->setSize(32,32,8,8);

    Prop2D *p=NULL, *pp=NULL;
    Grid *g=NULL;
    CharGrid *cg=NULL;
    

    // normal single
    p = new Prop2D();
    p->setDeck(deck);
    p->setIndex(1);
    p->setScl(64,64);
    p->setLoc(0,0);
    l->insertProp(p);
#if 0
    // with prim
    pp = new Prop2D();
    pp->setScl(1.0f);
    pp->setLoc(100,0);
    pp->addRect( Vec2(0,0), Vec2(-100,-100), Color(0,0,1,0.5) );
    pp->addLine( Vec2(0,0), Vec2(100,100), Color(1,0,0,1) );
    pp->addLine( Vec2(0,0), Vec2(100,-100), Color(0,1,0,1), 5 );
    l->insertProp(pp);
   

    // grid
    g = new Grid(4,4);
    for(int x=0;x<4;x++) {
        for(int y=0;y<4;y++) {
            //        g->set(x,y,80+((x+y)%10));
            g->set(x,y,((x+y)%3));
        }
    }
    g->setXFlip(0,0,true); 
    g->setYFlip(0,1,true);
    g->setUVRot(0,2,true);

    Prop2D *gp = new Prop2D();
    gp->setDeck(deck);
    gp->addGrid(g);
    gp->setScl(32)    ;
    gp->setLoc(50,0);
    gp->setRot(20);
    gp->setIndex(0);
    l->insertProp(gp);

    // uvrot 
    Prop2D *rotp = new Prop2D();
    rotp->setDeck(deck);
    rotp->setScl(32);
    rotp->setLoc(-300,-100);
    rotp->setUVRot(true);
    rotp->setIndex(0);
    l->insertProp(rotp);

    // chargrid
    Texture *ft = new Texture();
    ft->load("./assets/font_only.png");
    TileDeck *fdeck =new TileDeck();
    fdeck->setTexture(ft);
    fdeck->setSize(32,32,8,8);
    cg = new CharGrid(8,8);
    cg->ascii_offset = -32;
    cg->setDeck(fdeck);
    cg->printf(0,0,Color(1,1,1,1), "WHITE" );
    cg->printf(1,1,Color(1,0,0,1), "RED" );
    cg->printf(2,2,Color(0,1,0,1), "GREEN" );
    cg->printf(3,3,Color(0,0,1,1), "BLUE" );
    Prop2D *cgp = new Prop2D();
    cgp->addGrid(cg);
    cgp->setScl(16);
    cgp->setLoc(50,-100);
    l->insertProp(cgp);

    // children
    Prop2D *chp = new Prop2D();
    chp->setLoc(-200,-200);
    chp->setDeck(deck);
    chp->setScl(48);
    chp->setIndex(0);
    for(int i=0;i<8;i++) {
        Prop2D *p = new Prop2D();
        p->setDeck(deck);
        p->setLoc( chp->loc + Vec2( (i+1)*30,0 ) );
        p->setIndex(0);
        p->setScl( 36-i*3 );
        chp->addChild(p);
    }
    
    Prop2D *dynchp = new Prop2D();
    dynchp->setLoc( chp->loc + Vec2(0,-30) );
    dynchp->setIndex(0);
    dynchp->setScl(32);
    dynchp->setDeck(deck);
    chp->addChild(dynchp);
    l->insertProp(chp);
#endif    

#if 0
    // text
    wchar_t charcodes[] = L" !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~あいうえお";
    
    Font *font = new Font();
    font->loadFromTTF("./assets/cinecaption227.ttf", charcodes, 24 );
    TextBox *tbs[20];
    for(int i=0;i<20;i++) {
        tbs[i] = new TextBox();
        tbs[i]->setFont(font);
        tbs[i]->setString("A");
        tbs[i]->setScl(1+(float)i/10.0f);
        tbs[i]->setLoc(i*10-250,0);
        l->insertProp(tbs[i]);
    }
    TextBox *movtb = new TextBox();
    movtb->setFont(font);
    movtb->setString("ABCabc\n01234あいうえお");
    movtb->setScl(3);
    movtb->setLoc(0,-150);
    l->insertProp(movtb);

    // multiple viewport and layer
    Viewport *vp2 = new Viewport(); // testing multiple viewport scaling
    vp2->setSize(SCRW*retina,SCRH*retina); 
    vp2->setScale2D(SCRW*2,SCRH*2); 
    Camera *cam2 = new Camera();
    Layer *l2 = new Layer();
    l2->setViewport(vp2);
    l2->setCamera(cam2);
    Prop2D *p2 = new Prop2D();
    p2->setDeck(deck);
    p2->setScl(48,48);
    p2->setIndex(0);
    p2->setLoc(200,-200);
    l2->insertProp(p2);
    moyai_client->insertLayer(l2);

#endif
    
    // main loop

    while( !glfwWindowShouldClose(window) ){
        static int frame_counter = 0;
        static int loop_counter = 0;

        static double last_t = now();
        
        double t = now();
        double dt = t -last_t;
        last_t = t;

        double loop_start_at = t;
                
        frame_counter ++;
        loop_counter++;
        
        Vec2 at(::sin(t)*100,0);
        if(p){
            p->setLoc(at);
            if( loop_counter%21==0 )  p->setIndex( irange(0,3));
            static float rot=0;
            rot+=0.05;
            p->setRot(rot);
            p->setScl( 40 + ::sin(t/2) * 30 );
            if(pp) {
                pp->setRot(rot/2.0f);
            }

            if( loop_counter % 50 == 0 ) {
                float alpha = range(0.2, 1.0f);
                Color col(range(0,1),range(0,1),range(0,1),alpha);
                p->setColor(col);
            }
            if( loop_counter % 120 == 0 ) {
                switch(irange(0,3)) {
                case 0: p->setXFlip( irange(0,2)); break;
                case 1: p->setYFlip( irange(0,2)); break;
                case 2: p->setUVRot( irange(0,2)); break;
                }
            }            
        }

        int cnt = moyai_client->poll(dt);        

        if(g) {
            g->set( irange(0,4), irange(0,4), irange(0,3) );
            g->setColor( irange(0,4), irange(0,4), Color( range(0,1), range(0,1), range(0,1), range(0,1) ) );
        }
#if 0
        float tbr = 4 + ::sin(t)*3;
        movtb->setScl(tbr);

        Format fmt("%d", loop_counter);
        tbs[19]->setString(fmt.buf);
#endif
        
        // fps disp
        static double last_print_at = 0;
        if(last_print_at == 0){
            last_print_at = t;
        } else if( last_print_at < t-1 ){
        fprintf(stderr,"FPS:%d prop:%d drawcall:%d\n", frame_counter, cnt, moyai_client->last_draw_call_count  );
            frame_counter = 0;
            last_print_at = t;
        }

        moyai_client->render();
        //        print("drawcnt:%d", moyai_client->last_draw_call_count );
        if( g_keyboard->getKey( 'Q') ) {
            print("Q pressed");
            exit(0);
            break;
        }
        if( g_keyboard->getKey( 'L' ) ) {
            zoom_rate += 0.2;
            if( zoom_rate > 8 ) zoom_rate = 8;
        }
        if( g_keyboard->getKey( 'K' ) ) {
            zoom_rate -= 0.1;
            if( zoom_rate < 0.1 ) zoom_rate = 0.1;
        }
        viewport->setScale2D(SCRW * zoom_rate,SCRH * zoom_rate); 

        float scrollspeed = 10;
        if( g_keyboard->getKey( 'W' ) ) {
            center.y -= scrollspeed;
        }
        if( g_keyboard->getKey( 'S' ) ) {
            center.y += scrollspeed;
        }
        if( g_keyboard->getKey( 'A' ) ) {
            center.x += scrollspeed;
        }
        if( g_keyboard->getKey( 'D' ) ) {
            center.x -= scrollspeed;
        }
        camera->setLoc(center);

        
        if( g_keyboard->getKey( '1' ) ) {
            for(int i=0;i<50;i++) {
                Prop *p = new Particle(deck);
                l->insertProp(p);
            }
        }
        if( g_keyboard->getKey( '2' ) ) {
            if(cg) cg->printf(0,4, Color(1,1,1,1), Format( "CNT:%d", loop_counter).buf);
        }
#if 0        
        if( loop_counter % 25 == 0 ) {
            if( dynchp ) {
                bool res = chp->clearChild(dynchp);
                assert(res);
                delete dynchp;
                dynchp = NULL;
            } else {
                dynchp = new Prop2D();
                dynchp->setLoc( chp->loc + Vec2(0,-30) );
                dynchp->setIndex(0);
                dynchp->setScl(32);
                dynchp->setDeck(deck);
                chp->addChild(dynchp);
            }            
        }
#endif        
        glfwPollEvents();

        double loop_end_at = now();
        double loop_time = loop_end_at - loop_start_at;
        double ideal_frame_time = 1.0f / 60.0f;
        if(loop_time < ideal_frame_time ) {
            double to_sleep_sec = ideal_frame_time - loop_time;
            int to_sleep_msec = (int) (to_sleep_sec*1000);
            if( to_sleep_msec > 0 ) sleepMilliSec(to_sleep_msec);
        }
    }
    glfwTerminate();

    print("program finished");
    

    return 0;
}
Exemple #4
0
bool Prop2D::propPoll(double dt) {
	if( prop2DPoll(dt) == false ) return false;
    if(remote_vel.isZero()==false) { // for cloud syncing
        loc += remote_vel*dt;
    }

	// animation of index
	if(anim_curve){
		int previndex = index;
		bool finished = false;
		index = anim_curve->getIndex( accum_time - anim_start_at, &finished );
		if( index != previndex ){
			onIndexChanged(previndex);
		}
		if(finished) {
			onAnimFinished();
		}
	}
	// animation of scale
	if( seek_scl_time != 0 ){
		double elt = accum_time - seek_scl_started_at;
		if( elt > seek_scl_time ){
			scl = seek_scl_target;
			seek_scl_time = 0;
		} else {
			double rate = elt / seek_scl_time;
			scl.x = seek_scl_orig.x + ( seek_scl_target.x - seek_scl_orig.x ) * rate;
			scl.y = seek_scl_orig.y + ( seek_scl_target.y - seek_scl_orig.y ) * rate;
		}
	}
	// animation of rotation
	if( seek_rot_time != 0 ){
		double elt = accum_time - seek_rot_started_at;
		if( elt > seek_rot_time ){
			rot = seek_rot_target;
			seek_rot_time = 0;
		} else {
			double rate = elt / seek_rot_time;
			rot = seek_rot_orig + ( seek_rot_target - seek_rot_orig ) * rate;
		}
	}
	// animation of color
	if( seek_color_time != 0 ){
		double elt = accum_time - seek_color_started_at;
		if( elt > seek_color_time ){
			color = seek_color_target;
            if(seek_color_time!=0){
                onColorChanged();
            }
			seek_color_time = 0;
		} else {
			double rate = elt / seek_color_time;
			color = Color( seek_color_orig.r + ( seek_color_target.r - seek_color_orig.r ) * rate,
				seek_color_orig.g + ( seek_color_target.g - seek_color_orig.g ) * rate,
				seek_color_orig.b + ( seek_color_target.b - seek_color_orig.b ) * rate,
				seek_color_orig.a + ( seek_color_target.a - seek_color_orig.a ) * rate );
            onColorChanged();
		}
	}

	// children
	for(int i=0;i<children_num;i++){
		Prop2D *p = children[i];
		p->basePoll(dt);
	}

	return true;
}
Exemple #5
0
void Prop2D::render(Camera *cam, DrawBatchList *bl ) {
    if( debug_id ) {
        assertmsg(deck || grid_used_num > 0 || children_num > 0 || prim_drawer , "no deck/grid/prim_drawer is set. deck:%p grid:%d child:%d prim:%p", deck, grid_used_num, children_num, prim_drawer );
    }
    
	float camx=0.0f;
	float camy=0.0f;
	if(cam){
		camx = cam->loc.x;
		camy = cam->loc.y;
	}

	if( children_num > 0 && render_children_first ){
		for(int i=0;i<children_num;i++){
			Prop2D *p = (Prop2D*) children[i];
            if( p->visible ) {
                if( !p->parent_group ) {
                    p->parent_group = parent_group;
                }
                p->render( cam, bl );
            }
		}
	}

	if( grid_used_num > 0 ){
		glEnable(GL_TEXTURE_2D);
		glColor4f(color.r,color.g,color.b,color.a);        
		for(int i=0;i<grid_used_num;i++){
			Grid *grid = grids[i];
			if(!grid)break;
			if(!grid->visible)continue;
            if(!grid->index_table)continue;

			Deck *draw_deck = deck;
			if( grid->deck ) draw_deck = grid->deck;
			if( grid->fragment_shader ){
#if !(TARGET_IPHONE_SIMULATOR ||TARGET_OS_IPHONE || defined(__linux__) )
				glUseProgram(grid->fragment_shader->program );
#endif                
				grid->fragment_shader->updateUniforms();
			}

            if(!grid->mesh) {
                //                print("new grid mesh! wh:%d,%d", grid->width, grid->height );
                grid->mesh = new Mesh();
                VertexFormat *vf = DrawBatch::getVertexFormat( VFTYPE_COORD_COLOR_UV );
                IndexBuffer *ib = new IndexBuffer();
                VertexBuffer *vb = new VertexBuffer();
                vb->setFormat(vf);
                /*
                  3+--+--+--+--+
                   |  |  |  |  |
                  2+--+--+--+--+
                   |  |  |  |  |
                  1+--+--+--+--+
                   |  |  |  |  |
                  0+--+--+--+--+
                   0  1  2  3  4
                 */
                int quad_num = grid->width * grid->height;
                int triangle_num = quad_num * 2;
                int vert_num = quad_num * 4; // Can't share vertices because each vert has different UVs 
                vb->reserve( vert_num);
                ib->reserve( triangle_num*3 );
                grid->mesh->setVertexBuffer(vb);
                grid->mesh->setIndexBuffer(ib);
                grid->mesh->setPrimType( GL_TRIANGLES );

                grid->uv_changed = true;
                grid->color_changed = true;
            }

            if( grid->uv_changed || grid->color_changed ) {
                if(grid->debug) {
                    print("debug:%d Grid changed: uv:%d col:%d", grid->debug, grid->uv_changed, grid->color_changed );
                }
                grid->uv_changed = false;
                grid->color_changed = false;
                
                VertexBuffer *vb = grid->mesh->vb;
                IndexBuffer *ib = grid->mesh->ib;
                vb->unbless();
                ib->unbless();

                int quad_cnt=0;
                for(int y=0;y<grid->height;y++) {
                    for(int x=0;x<grid->width;x++) {
                        int ind = x+y*grid->width;
                        if(grid->debug) {
                            if(grid->texofs_table) {
                                prt("%.2f,%.2f ", grid->texofs_table[ind].x, grid->texofs_table[ind].y );
                            } else if( grid->index_table ) {
                                prt("%3d ", grid->index_table[ind] );
                            }
                        }
                        if( grid->index_table[ind] == Grid::GRID_NOT_USED ) continue;
                        
                        
                        Vec2 left_bottom, right_top;
                        float u0,v0,u1,v1;
                        draw_deck->getUVFromIndex( grid->index_table[ind], &u0,&v0,&u1,&v1,0,0,grid->uv_margin);
                        if(grid->texofs_table) {
                            float u_per_cell = draw_deck->getUperCell();
                            float v_per_cell = draw_deck->getVperCell();
                            u0 += grid->texofs_table[ind].x * u_per_cell;
                            v0 += grid->texofs_table[ind].y * v_per_cell;
                            u1 += grid->texofs_table[ind].x * u_per_cell;
                            v1 += grid->texofs_table[ind].y * v_per_cell;
                        }

                        //
                        // Q (u0,v0) - R (u1,v0)      top-bottom upside down.
                        //      |           |
                        //      |           |                        
                        // P (u0,v1) - S (u1,v1)
                        //
                        if(grid->xflip_table && grid->xflip_table[ind]) {
                            swapf( &u0, &u1 );
                        }
                        if(grid->yflip_table && grid->yflip_table[ind]) {
                            swapf( &v0, &v1 );
                        }
                        Vec2 uv_p(u0,v1), uv_q(u0,v0), uv_r(u1,v0), uv_s(u1,v1);

                        
                        // left bottom
                        const float d = 1;
                        int vi = quad_cnt * 4;
                        vb->setCoord(vi,Vec3(d*x-enfat_epsilon,d*y-enfat_epsilon,0));
                        if(grid->rot_table && grid->rot_table[ind]) vb->setUV(vi,uv_s); else vb->setUV(vi,uv_p);
                        if(grid->color_table) vb->setColor(vi, grid->color_table[ind]); else vb->setColor(vi, Color(1,1,1,1));
                        // right bottom
                        vb->setCoord(vi+1,Vec3(d*(x+1)+enfat_epsilon,d*y-enfat_epsilon,0));
                        if(grid->rot_table && grid->rot_table[ind]) vb->setUV(vi+1,uv_r); else vb->setUV(vi+1,uv_s);                        
                        if(grid->color_table) vb->setColor(vi+1,grid->color_table[ind]); else vb->setColor(vi+1, Color(1,1,1,1));
                        // left top
                        vb->setCoord(vi+2,Vec3(d*x-enfat_epsilon,d*(y+1)+enfat_epsilon,0));
                        if(grid->rot_table && grid->rot_table[ind]) vb->setUV(vi+2,uv_p); else vb->setUV(vi+2,uv_q);
                        if(grid->color_table) vb->setColor(vi+2,grid->color_table[ind]); else vb->setColor(vi+2, Color(1,1,1,1));
                        // right top
                        vb->setCoord(vi+3,Vec3(d*(x+1)+enfat_epsilon,d*(y+1)+enfat_epsilon,0));
                        if(grid->rot_table && grid->rot_table[ind]) vb->setUV(vi+3,uv_q); else vb->setUV(vi+3,uv_r);
                        if(grid->color_table) vb->setColor(vi+3,grid->color_table[ind]); else vb->setColor(vi+3, Color(1,1,1,1));

                        // TODO: no need to update index every time it changes.
                       
                        int indi = quad_cnt * 6; // 2 triangles = 6 verts per quad
                        ib->setIndex(indi++, quad_cnt*4+0 );
                        ib->setIndex(indi++, quad_cnt*4+2 );
                        ib->setIndex(indi++, quad_cnt*4+1 );
                        ib->setIndex(indi++, quad_cnt*4+1 );
                        ib->setIndex(indi++, quad_cnt*4+2 );
                        ib->setIndex(indi++, quad_cnt*4+3 );

                        quad_cnt++; // next quad!
                    }
                    if(grid->debug) print("");
                }
                ib->setRenderLen(quad_cnt*6);
            } 

            
            // draw
            if(!draw_deck) {
                print("no tex? (grid)");
                continue;
            }
            if( grid->mesh == NULL || grid->mesh->hasIndexesToRender() == false ) {
                continue;
            }
            FragmentShader *fs = fragment_shader;
            if( grid->fragment_shader ) fs = grid->fragment_shader;
            //            print("appendMesh, tex:%d vn:%d rn:%d", draw_deck->tex->tex, grid->mesh->vb->array_len, grid->mesh->ib->render_len );
            Vec2 finloc(loc.x+grid->rel_loc.x, loc.y+grid->rel_loc.y);
            Vec2 finscl(scl.x*grid->rel_scl.x, scl.y*grid->rel_scl.y);
            if(!fs)fs=default_fs;
            bl->appendMesh( getViewport(), fs, getBlendType(), draw_deck->tex->tex, finloc - Vec2(camx,camy), finscl, rot, grid->mesh, copy_mesh_at_draw );
		}
	}

	if(deck && index >= 0 ){
        float u0,v0,u1,v1;
        deck->getUVFromIndex( index, &u0,&v0,&u1,&v1,0,0,uv_margin);
        if(xflip) {
            swapf(&u0,&u1);
        }
        if(yflip) {
            swapf(&v0,&v1);
        }
        // Q (u0,v0) - R (u1,v0)      top-bottom upside down.
        //      |           |
        //      |           |                        
        // P (u0,v1) - S (u1,v1)
        Vec2 uv_p(u0,v1), uv_q(u0,v0), uv_r(u1,v0), uv_s(u1,v1);
        if(uvrot) {
            Vec2 tmp = uv_p;
            uv_p = uv_s;
            uv_s = uv_r;
            uv_r = uv_q;
            uv_q = tmp;
        }
        if(!fragment_shader)fragment_shader=default_fs;
        bl->appendSprite1( getViewport(),
                           fragment_shader,
                           getBlendType(),
                           deck->tex->tex,
                           color,
                           loc - Vec2(camx,camy) + draw_offset,
                           scl,
                           rot,
                           uv_p,
                           uv_q,
                           uv_r,
                           uv_s
                           );
	}

	if( children_num > 0 && (render_children_first == false) ){
		for(int i=0;i<children_num;i++){
			Prop2D *p = (Prop2D*) children[i];
			if(p->visible) {
                if( !p->parent_group ) {
                    p->parent_group = parent_group;
                }
                p->render( cam, bl );
            }
		}
	}

	// primitives should go over image sprites
	if( prim_drawer ){
		prim_drawer->drawAll( bl, getViewport(), loc - Vec2(camx,camy),scl,rot);
	}
}