void ZoomCamera::adjust(const Bounds2D& bounds, bool adjust_distance) { //center camera on bounds vec2 centre = bounds.centre(); //adjust by screen ratio dest.x = centre.x; dest.y = centre.y; if(!adjust_distance) return; //scale by 10% so we dont have stuff right on the edge of the screen float width = bounds.width() * padding; float height = bounds.height() * padding; float aspect_ratio = display.width / (float) display.height; if(aspect_ratio < 1.0) { height /= aspect_ratio; } else { width /= aspect_ratio; } //calc visible width of the opposite wall at a distance of 1 this fov float toa = tan( fov * 0.5f * DEGREES_TO_RADIANS ) * 2.0; float distance; //TOA = tan = opposite/adjacent (distance = adjacent) //use the larger side of the box //cropping: vertical, horizontal or none if(gGourceSettings.crop_vertical) { distance = width / toa; } else if (gGourceSettings.crop_horizontal) { distance = height / toa; } else { if(width >= height) { distance = width / toa; } else { distance = height / toa; } } //debugLog("toa %.2f, distance %.2f width %.2f height %.2f dratio %.2f\n", toa, distance, width, height, dratio); //check bounds are valid if(distance < min_distance) distance = min_distance; if(distance > max_distance) distance = max_distance; this->dest.z = -distance; }
void RDirNode::updateQuadItemBounds() { float radius = getRadius(); //set bounds Bounds2D bounds; bounds.update(pos - vec2f(radius,radius)); bounds.update(pos + vec2f(radius,radius)); quadItemBounds = bounds; }
void Pawn::updateQuadItemBounds() { float ratio = icon->h / (float) icon->w; float halfsize = size * 0.5f; //set bounds Bounds2D bounds; bounds.update(pos - vec2f(halfsize,halfsize)); bounds.update(pos + vec2f(halfsize,halfsize)); quadItemBounds = bounds; }
void Gource::updateCamera(float dt) { //camera tracking Bounds2D cambounds; bool auto_rotate = !manual_rotate && !gGourceSettings.disable_auto_rotate; if(backgroundSelected) { Bounds2D mousebounds; mousebounds.update(backgroundPos); cambounds = mousebounds; auto_rotate = false; } else if(track_users && (selectedFile !=0 || selectedUser !=0)) { Bounds2D focusbounds; vec3f camerapos = camera.getPos(); if(selectedUser !=0) focusbounds.update(selectedUser->getPos()); if(selectedFile !=0) focusbounds.update(selectedFile->getAbsolutePos()); cambounds = focusbounds; } else { if(track_users && idle_time==0) cambounds = user_bounds; else cambounds = dir_bounds; } camera.adjust(cambounds); camera.logic(dt); //automatically rotate camera if(auto_rotate) { float dratio = 0.95f; Uint8 ms = SDL_GetMouseState(0,0); bool rightmouse = ms & SDL_BUTTON(SDL_BUTTON_RIGHT); if(!rightmouse && dir_bounds.area() > 10000.0f) { float ratio = dir_bounds.width() / dir_bounds.height(); if(ratio<dratio) { //rotate up to 90 degrees a second rotate_angle = 90.0f * (dratio-ratio) * dt * DEGREES_TO_RADIANS; } } } }
void ZoomCamera::adjust(Bounds2D& bounds) { //center camera on bounds //scale by 10% so we dont have stuff right on the edge of the screen float width = bounds.width() * padding; float height = bounds.height() * padding; vec2f centre = bounds.centre(); //adjust by screen ratio float dratio = display.height / (float) display.width; if(dratio > 1.0) { height /= dratio; } else { width *= dratio; } //calc visible width of the opposite wall at a distance of 1 this fov float toa = tan( getFov() * 0.5f * DEGREES_TO_RADIANS ) * 2.0; float distance; //TOA = tan = opposite/adjacent (distance = adjacent) //use the larger side of the box //cropping: vertical, horizontal or none if(gGourceSettings.crop_vertical) { distance = width / toa ; } else if (gGourceSettings.crop_horizontal) { distance = height / toa ; } else { if(width > height) { distance = width / toa ; } else { distance = height / toa ; } } //debugLog("toa %.2f, distance %.2f width %.2f height %.2f dratio %.2f\n", toa, distance, width, height, dratio); //check bounds are valid if(distance < min_distance) distance = min_distance; if(distance > max_distance) distance = max_distance; this->dest = vec3f(centre.x, centre.y, -distance); }
int QuadNode::getItemsInBounds(std::vector<QuadItem*>& itemvec, Bounds2D& bounds) { if(items.size()>0) { int items_added = 0; for(std::list<QuadItem*>::iterator it = items.begin(); it != items.end(); it++) { QuadItem* oi = (*it); itemvec.push_back(oi); items_added++; } return items_added; } if(children.size()==0) return 0; int count = 0; //for each 4 corners for(int i=0;i<4;i++) { if(!children[i]->empty() && bounds.overlaps(children[i]->bounds)) { count += children[i]->getItemsInBounds(itemvec, bounds); } } return count; }
int QuadNode::getItemsInBounds(std::set<QuadItem*>& itemset, Bounds2D& bounds) const{ if(!items.empty()) { int items_added = 0; for(std::list<QuadItem*>::const_iterator it = items.begin(); it != items.end(); it++) { QuadItem* oi = (*it); itemset.insert(oi); items_added++; } return items_added; } if(children.empty()) return 0; int count = 0; //for each 4 corners for(int i=0;i<4;i++) { if(!children[i]->empty() && bounds.overlaps(children[i]->bounds)) { count += children[i]->getItemsInBounds(itemset, bounds); } } return count; }
void Gource::updateCamera(float dt) { //camera tracking if(track_users && (selectedFile !=0 || selectedUser !=0)) { Bounds2D focusbounds; vec3f camerapos = camera.getPos(); if(selectedUser !=0) focusbounds.update(selectedUser->getPos()); if(selectedFile !=0) focusbounds.update(selectedFile->getAbsolutePos()); camera.adjust(focusbounds); } else { if(track_users && idle_time==0) camera.adjust(user_bounds); else camera.adjust(dir_bounds); } camera.logic(dt); }
void QuadNode::visitItemsInBounds(const Bounds2D & bounds, VisitFunctor<QuadItem> & visit){ if(!items.empty()) { for(std::list<QuadItem*>::const_iterator it = items.begin(); it != items.end(); it++) visit(*it); }else if(!children.empty()){ //visit each corner for(int i=0;i<4;i++) if(!children[i]->empty() && bounds.overlaps(children[i]->bounds)) children[i]->visitItemsInBounds(bounds, visit); } }
void RDirNode::logic(float dt, Bounds2D& bounds) { //move move(dt); updateSpline(dt); //update node normal if(parent != 0) { node_normal = (pos - parent->getPos()).normal(); } bounds.update(pos); //update files for(std::list<RFile*>::iterator it = files.begin(); it!=files.end(); it++) { RFile* f = *it; f->logic(dt); } //update child nodes for(std::list<RDirNode*>::iterator it = children.begin(); it != children.end(); it++) { RDirNode* node = (*it); node->logic(dt, bounds); } //update colour calcColour(); //update tickers if(visible) since_node_visible += dt; since_last_file_change += dt; since_last_node_change += dt; }
void Gource::draw(float t, float dt) { dt = std::min<float>(dt, gGourceMaxDelta * time_scale); display.setClearColour(background_colour); display.clear(); if(draw_loading) { loadingScreen(); draw_loading = false; return; } //camera tracking if(track_users && (selectedFile !=0 || selectedUser !=0)) { Bounds2D focusbounds; vec3f camerapos = camera.getPos(); if(selectedUser !=0) focusbounds.update(selectedUser->getPos()); if(selectedFile !=0) focusbounds.update(selectedFile->getAbsolutePos()); camera.adjust(focusbounds); } else { if(track_users && idle_time==0) camera.adjust(user_bounds); else camera.adjust(dir_bounds); } camera.logic(dt); Frustum frustum(camera); trace_time = SDL_GetTicks(); mousetrace(frustum,dt); trace_time = SDL_GetTicks() - trace_time; glMatrixMode(GL_PROJECTION); glLoadIdentity(); camera.focus(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); draw_tree_time = SDL_GetTicks(); root->calcEdges(); //switch to 2d glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, display.width, display.height, 0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_TEXTURE_2D); //draw edges root->drawEdgeShadows(dt); root->drawEdges(dt); //switch back glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); //draw shadows if(!gGourceHideUsers) { for(std::map<std::string,RUser*>::iterator it = users.begin(); it!=users.end(); it++) { it->second->drawShadow(dt); } } root->drawShadows(frustum, dt); //draw actions for(std::map<std::string,RUser*>::iterator it = users.begin(); it!=users.end(); it++) { it->second->drawActions(dt); } glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(0.0, 1.0, 0.0, 1.0); trace_debug ? root->drawSimple(frustum,dt) : root->drawFiles(frustum,dt); draw_tree_time = SDL_GetTicks() - draw_tree_time; glColor4f(1.0, 1.0, 0.0, 1.0); for(std::map<std::string,RUser*>::iterator it = users.begin(); it!=users.end(); it++) { trace_debug ? it->second->drawSimple(dt) : it->second->draw(dt); } glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); root->drawNames(font,frustum); if(!gGourceHideUsernames) { for(std::map<std::string,RUser*>::iterator it = users.begin(); it!=users.end(); it++) { it->second->drawName(); } } //draw selected item names again so they are over the top if(selectedUser !=0) selectedUser->drawName(); if(selectedFile !=0) { vec2f dirpos = selectedFile->getDir()->getPos(); glPushMatrix(); glTranslatef(dirpos.x, dirpos.y, 0.0); selectedFile->drawName(); glPopMatrix(); } if(debug) { glDisable(GL_TEXTURE_2D); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); track_users ? user_bounds.draw() : dir_bounds.draw(); } if(gGourceQuadTreeDebug) { glDisable(GL_TEXTURE_2D); glColor4f(0.0f, 1.0f, 0.0f, 1.0f); glLineWidth(1.0); dirNodeTree->outline(); glColor4f(0.0f, 1.0f, 1.0f, 1.0f); userTree->outline(); } glColor4f(1.0f, 1.0f, 1.0f, 1.0f); display.mode2D(); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_TEXTURE_2D); vec3f campos = camera.getPos(); float width = static_cast<float>(display.width); float height = static_cast<float>(display.height); float half_width = width/2.0f; float half_height = height/2.0f; if(!gGourceHideDate) { fontmedium.draw(half_width - date_x_offset, 20.0f, displaydate); } if(splash>0.0f) { float logowidth = fontlarge.getWidth("Gource"); float logoheight = 100.0f; float cwidth = font.getWidth("Software Version Control Visualization"); float awidth = font.getWidth("(C) 2009 Andrew Caudwell"); vec2f corner(half_width - logowidth/2.0f - 30.0f, half_height - 40.0f); glDisable(GL_TEXTURE_2D); glColor4f(0.0f, 0.5f, 1.0f, splash * 0.015f); glBegin(GL_QUADS); glVertex2f(0.0f, corner.y); glVertex2f(0.0f, corner.y + logoheight); glVertex2f(width, corner.y + logoheight); glVertex2f(width, corner.y); glEnd(); glEnable(GL_TEXTURE_2D); glColor4f(1.0f,1.0f,1.0f,1.0f); fontlarge.draw(half_width - logowidth/2.0f,half_height - 30.0f, "Gource"); font.draw(half_width - cwidth/2.0f,half_height + 10.0f, "Software Version Control Visualization"); font.draw(half_width - awidth/2.0f,half_height + 30.0f, "(C) 2009 Andrew Caudwell"); } if(debug) { font.print(0,20, "FPS: %.2f", fps); font.print(0,60,"Users: %d", users.size()); font.print(0,80,"Files: %d", files.size()); font.print(0,100,"Dirs: %d", gGourceDirMap.size()); font.print(0,120,"Log Position: %.2f", commitlog->getPercent()); font.print(0,140,"Camera: (%.2f, %.2f, %.2f)", campos.x, campos.y, campos.z); font.print(0,160,"Gravity: %.2f", gGourceForceGravity); font.print(0,180,"Update Tree: %u ms", update_dir_tree_time); font.print(0,200,"Draw Tree: %u ms", draw_tree_time); font.print(0,220,"Mouse Trace: %u ms", trace_time); font.print(0,240,"Logic Time: %u ms", logic_time); font.print(0,260,"Draw Time: %u ms", SDL_GetTicks() - draw_time); font.print(0,280,"File Inner Loops: %d", gGourceFileInnerLoops); font.print(0,300,"User Inner Loops: %d", gGourceUserInnerLoops); font.print(0,320,"Dir Inner Loops: %d (QTree items = %d, nodes = %d)", gGourceDirNodeInnerLoops, dirNodeTree->item_count, dirNodeTree->node_count); if(selectedUser != 0) { } if(selectedFile != 0) { font.print(0.0f,360.0f,"%s: %d files (%d visible)", selectedFile->getDir()->getPath().c_str(), selectedFile->getDir()->fileCount(), selectedFile->getDir()->visibleFileCount()); } } glDisable(GL_TEXTURE_2D); if(canSeek()) slider.draw(dt); mousemoved=false; mouseclicked=false; }