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 ); } }
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; }
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; }
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; }
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); } }