Отрисовка углового сектора текстуры (3 стр)
Автор: Flamer
Ну и, в завершение, функция отрисовки углового сектора:
Автор: Flamer
Ну и, в завершение, функция отрисовки углового сектора:
void RenderAngularSector(HGE* hge , hgeSprite* sprite // можно спрайт передать , hgeAnimation* animation // а можно анимацию , int screen_x // точка, в которой рисовать на экране , int screen_y , int x_start // точка внутри прямоугольника (относительные координаты) , int y_start , double origAngleA // начальное значение угла (радиан) , double origAngleB // конечное значение угла (радиан) ) { // Let's rock! HTEXTURE tex = 0; int blend = BLEND_DEFAULT; float x,y,w,h; // получаем актуальные координаты по точкам на текстуре int tex_width = 0; int tex_height = 0; if( sprite) { // у меня в закомментированных переменных хранится начальное смещение // текстурных координат, передаваемое в конструктор hgeSprite x = 0; //this->m_iTextureX; y = 0; //this->m_iTextureY; tex = sprite->GetTexture( ); blend = sprite->GetBlendMode( ); // Это кака и нагружает! На самом деле я все это храню в классе. w = sprite->GetWidth( ); h = sprite->GetHeight( ); tex_width = hge->Texture_GetWidth( tex,true); tex_height = hge->Texture_GetHeight( tex,true); } else if( animation) { // у меня в закомментированных переменных хранится начальное смещение // текстурных координат, передаваемое в конструктор hgeAnimation x = 0; //this->m_iTextureX; y = 0; //this->m_iTextureY; tex = animation->GetTexture( ); blend = animation->GetBlendMode( ); // Это кака и нагружает! На самом деле я все это храню в классе. w = animation->GetWidth( ); h = animation->GetHeight( ); tex_width = hge->Texture_GetWidth( tex,true); tex_height = hge->Texture_GetHeight( tex,true); // получили номер текущего кадра int cur_frame = animation->GetFrame( ); // высчитываем координаты сдвига относительно переданной точки int ncols = tex_width / w; int tx1 = x + cur_frame*w; int ty1 = y; if( tx1 > tex_width-w) { cur_frame -= int( tex_width - x) / int( w); tx1 = w * ( cur_frame%ncols); ty1 += h * ( 1 + cur_frame/ncols); } // if // тут получили координаты текущего фрейма анимации в текстуре x = tx1; y = ty1; } // if(animation) // транслируем относительные координаты точки внутри прямоугольника в абсолютные x_start += x; y_start += y; const double MAGIC = M_PI*2; // для трансляции направления вектора в правильную сторону, // т.к. у нас координаты 0*PI в радианах справа // теперь транслируем углы в нормальные координаты, чтобы правильно // работал тест пересечений со сторонами double angleA = MAGIC - origAngleA; double angleB = MAGIC - origAngleB; // идем по часовой стрелке от первого угла ко второму int vec_len = max( w,h)*2; // получаем длину вектора, чтобы он гарантированно пересекся со сторонами // вычисляем конечную точку первого вектора double x_end = x_start + cosf( angleA)*vec_len; double y_end = y_start + sinf( angleA)*vec_len; hgeVector startPoint( x_start,y_start); // начальная точка векторов hgeVector endPoint1( x_end,y_end); // конечная точка первого вектора // вычисляем конечную точку второго вектора x_end = x_start + cosf( angleB)*vec_len; y_end = y_start + sinf( angleB)*vec_len; hgeVector endPoint2( x_end,y_end); // конечная точка второго вектора // создаем вектора вершин прямоугольника hgeVector topLeftCorner( x,y); // левый/верхний угол hgeVector topRightCorner( x+w,y); // правый/верхний угол hgeVector rightBottomCorner( x+w,y+h); // правый/нижний угол hgeVector leftBottomCorner( x,y+h); // левый/нижний угол // точки вершин прямоугольника, пригодятся для обхода вершин hgeVector rectCoords[4] = {topLeftCorner,topRightCorner,rightBottomCorner,leftBottomCorner}; std::vector<side_point> points; // вычисленные точки // проверяем первый вектор (для угла a) bool cross_found = false; // пересекаемся справа? CROSS_RESULT cr = Crossing( startPoint,endPoint1,topRightCorner,rightBottomCorner); if( cr.type == ctOnBounds || cr.type == ctInBounds) { // пересекаемся справа! side_point s; s.side = wsRight; s.pt = cr.pt; points.push_back( s); cross_found = true; } if( !cross_found) { // пересекаемся снизу? cr = Crossing( startPoint,endPoint1,leftBottomCorner,rightBottomCorner); if( cr.type == ctOnBounds || cr.type == ctInBounds) { // пересекаемся снизу! side_point s; s.side = wsBottom; s.pt = cr.pt; points.push_back( s); cross_found = true; } } if( !cross_found) { // пересекаемся слева? cr = Crossing( startPoint,endPoint1,topLeftCorner,leftBottomCorner); if( cr.type == ctOnBounds || cr.type == ctInBounds) { // пересекаемся слева! side_point s; s.side = wsLeft; s.pt = cr.pt; points.push_back( s); cross_found = true; } } if( !cross_found) { // пересекаемся сверху? cr = Crossing( startPoint,endPoint1,topLeftCorner,topRightCorner); if( cr.type == ctOnBounds || cr.type == ctInBounds) { // пересекаемся сверху! side_point s; s.side = wsTop; s.pt = cr.pt; points.push_back( s); cross_found = true; } } // все, теперь мы имеем в векторе начальную точку на одной из сторон. // теперь надо получить сторону, на которой точка второго вектора. side_point secondVecCross; cross_found = false; // пересекаемся справа? cr = Crossing( startPoint,endPoint2,topRightCorner,rightBottomCorner); if( cr.type == ctOnBounds || cr.type == ctInBounds) { // пересекаемся справа! secondVecCross.side = wsRight; secondVecCross.pt = cr.pt; cross_found = true; } if( !cross_found) { // пересекаемся снизу? cr = Crossing( startPoint,endPoint2,leftBottomCorner,rightBottomCorner); if( cr.type == ctOnBounds || cr.type == ctInBounds) { // пересекаемся снизу! secondVecCross.side = wsBottom; secondVecCross.pt = cr.pt; cross_found = true; } } if( !cross_found) { // пересекаемся слева? cr = Crossing( startPoint,endPoint2,topLeftCorner,leftBottomCorner); if( cr.type == ctOnBounds || cr.type == ctInBounds) { // пересекаемся слева! secondVecCross.side = wsLeft; secondVecCross.pt = cr.pt; cross_found = true; } } if( !cross_found) { // пересекаемся сверху? cr = Crossing( startPoint,endPoint2,topLeftCorner,topRightCorner); if( cr.type == ctOnBounds || cr.type == ctInBounds) { // пересекаемся сверху! secondVecCross.side = wsTop; secondVecCross.pt = cr.pt; cross_found = true; } } // тут мы имеем две точки на сторонах прямоугольника. По часовой стрелке // проходим по всем вершинам между первой и второй точками и сохраняем их // в массив для будущего использования. // ВСЕ ТОЧКИ УЖЕ В АВСОЛЮТНЫХ ТЕКСТУРНЫХ КООРДИНАТАХ! if( points.size( ) > 0) // есть первая точка { side_point firstVecCross = points[0]; // точка пересечения первого вектора int which_side = firstVecCross.side; // счетчик вершин // в which_side индекс, на какой стороне лежит точка. // если она лежит на левой стороне - следующая точка - левый/верхний угол и т.д. // если не было заворота за хотя бы одну вершину - угол слишком мал, // и не надо делать do, надо делать while !!! bool has_wrap = false; // флаг заворота за вершину if( firstVecCross.side == secondVecCross.side) // на одной стороне прямоугольника очутились { if( firstVecCross.side == wsRight) // на правой стороне столкнулись { // если вторая точка лежит выше - быть обходу вершин if( secondVecCross.pt.y < firstVecCross.pt.y) has_wrap = true; } else if( firstVecCross.side == wsTop) // на верхней стороне столкнулись { // если вторая точка лежит левее - быть обходу вершин if( secondVecCross.pt.x < firstVecCross.pt.x) has_wrap = true; } else if( firstVecCross.side == wsLeft) // на левой стороне столкнулись { // если вторая точка лежит ниже - быть обходу вершин if( secondVecCross.pt.y > firstVecCross.pt.y) has_wrap = true; } else if( firstVecCross.side == wsBottom) // на нижней стороне столкнулись { // если вторая точка лежит правее - быть обходу вершин if( secondVecCross.pt.x > firstVecCross.pt.x) has_wrap = true; } } // if // проходим по всем точкам, пока не достигнем стороны, на которую опирается второй вектор. if( !has_wrap) // не было заворота второго вектора за одну из вершин { while( which_side != secondVecCross.side) { // теперь в which_side у нас лежит индекс вершины, который надо добавить к точкам side_point new_pt; new_pt.pt = rectCoords[which_side]; points.push_back( new_pt); // добавляем индекс вершины // прибавляем индекс и смотрим за переполнением. which_side = which_side + 1; if( which_side > wsBottom) // переполнились, начинаем по кругу which_side = wsLeft; } // while } else // был заворот второго угла хотя бы за одну вершину { do { // теперь в which_side у нас лежит индекс вершины, который надо добавить к точкам side_point new_pt; new_pt.pt = rectCoords[which_side]; points.push_back( new_pt); // добавляем индекс вершины // прибавляем индекс и смотрим за переполнением. which_side = which_side + 1; if( which_side > wsBottom) // переполнились, начинаем по кругу which_side = wsLeft; } while( which_side != secondVecCross.side); } // добавляем конечную точку points.push_back( secondVecCross); // теперь у нас есть все точки пересечения векторов, включая точки вершин, // следовательно мы можем строить треугольники. // проходим по всем точкам слева-направо, берем соседние вершины и // используем их для треугольника. for( size_t i =1;i< points.size( );i++) { side_point point1 = points[i-1]; side_point point2 = points[i]; // начинаем со startPoint, через point1 к point2 - это и есть очередной треугольник. // при отрисовке учитываем сдвиг экранных координат и то, что все координаты - // абсолютные текстурные, и при выводе на экран сдвигом x,y надо пренебречь. hgeTriple triple; triple.tex = tex; triple.blend = blend; triple.v[0].col = 0xFFFFFFFF; triple.v[1].col = 0xFFFFFFFF; triple.v[2].col = 0xFFFFFFFF; triple.v[0].z = 1.0; triple.v[1].z = 1.0; triple.v[2].z = 1.0; triple.v[0].x = startPoint.x - x + screen_x; triple.v[0].y = startPoint.y - y + screen_y; triple.v[0].tx = startPoint.x/tex_width; triple.v[0].ty = startPoint.y/tex_height; triple.v[1].x = point1.pt.x - x + screen_x; triple.v[1].y = point1.pt.y - y + screen_y; triple.v[1].tx = point1.pt.x/tex_width; triple.v[1].ty = point1.pt.y/tex_height; triple.v[2].x = point2.pt.x - x + screen_x; triple.v[2].y = point2.pt.y - y + screen_y; triple.v[2].tx = point2.pt.x/tex_width; triple.v[2].ty = point2.pt.y/tex_height; // рисуем треугольник hge->Gfx_RenderTriple( &triple); } // for } // if(points.size() > 0) }
Ну и, как результат всей этой халабуды, вызов
RenderAngularSector(hge, sprite, NULL, 100, 100, 128, 128, M_PI/2 , M_PI);
для спрайта размерами 256x256 должен вывести текстуру с выпиленной верхней/левой четвертью. В следующий части будет пример с исходником.
З.Ы. Понятное дело, что декомпозицией тут и не пахнет - так ведь сваливал в кучу, выдирая из класса. На самом деле можно все красиво оформить, но пойнт данного поста не в этом, как вы уже догадались. И да - возможно, многое можно было сделать проще, но мне было не до этого, честно говоря. Главное было - чтобы оно заработало.
2 января 2011
Комментарии [6]