Как эффективно выполнить отсечение изображения в родительском RECT?

Итак,
я экспериментирую с DIRECTX API на C++ и разрабатываю интерфейс спрайтов, который выполняет отсечение внутри родительских RECT, например окно пользовательского интерфейса или другой спрайт или что-то еще.

Это потому, что позже я собираюсь создать функцию прокрутки для окна пользовательского интерфейса.

Я думаю, что изображение было бы уместным, чтобы продемонстрировать, чего я пытаюсь достичь.
Clipping

Для выполнения вычислений отсечения требуются как минимум четыре переменные/структуры (из того, что я могу различить):

  • Родитель RECT: границы "отсечения"
  • D3DXIMAGE_INFO: содержит информацию об изображении, такую ​​как ширина и высота.
  • Положение спрайта
  • Нарисуйте RECT: для функции LPD3DXSPRITE->Draw(). В основном, какая часть изображения должна быть нарисована. Здесь происходит «отсечение».

Теперь я думаю, что было бы запутанно, если бы я показал вам весь свой интерфейс и его внутреннюю работу и то, как он обрабатывает переменные.

Вместо этого
этот фрагмент кода демонстрирует, как я сейчас вычисляю отсечение.

void ClippingCalculation(){
    RECT parent_bounds, draw_rect;
    D3DXVECTOR2 sprite_position; //Relative to parent rect
    D3DXIMAGE_INFO img_info;

    //Fill image info
    D3DXGetImageInfoFromFile("image.png", &img_info); //Image is 100x100px

    //Define the rects
    SetRect(&parent_bounds, 0, 0, 200, 200);
    SetRect(&draw_rect, 0, 0, img_info.Width, img_info.Height); //Draw the entire image by default

    //Give it a position that makes a portion go out of parent bounds
    sprite_position = D3DXVECTOR2(150, 150); // 3/4 of the entire image is out of bounds

    //Check if completely within bounds
    bool min_x = (sprite_position.x > parent_bounds.left),
         min_y = (sprite_position.y > parent_bounds.top),
         max_x = (sprite_position.x+img_info.Width < parent_bounds.right),
         max_y = (sprite_position.y+img_info.Height < parent_bounds.bottom);

    if(min_x && min_y && max_x && max_y) 
         return; //No clipping needs to be done

    float delta_top = parent_bounds.top - sprite_position.y,
          delta_left = parent_bounds.left - sprite_position.x,    
          delta_bottom = parent_bounds.bottom - sprite_position.y,
          delta_right = parent_bounds.right - sprite_position.x;

    //Check if completely outside bounds
    bool out_left = (delta_left >= img_info.Width),
         out_top = (delta_top >= img_info.Height),
         out_bottom = (delta_bottom >= img_info.Height),
         out_right = (delta_right >= img_info.Width);

    if(out_left || out_top || out_bottom || out_right){ 
         //No drawing needs to be done, it's not even visible
         return; //No clipping
    }

    if(!min_x) draw_rect.left = delta_left;

    if(!min_x) draw_rect.top = delta_top;

    if(!max_x) draw_rect.right = delta_right;

    if(!max_y) draw_rect.bottom = delta_bottom;

    return;
}

Мои вопросы:

  1. Вы сразу видите что-то не так с кодом?
  2. Это эффективно или неэффективно?
    Отсечение выполняется каждый раз, когда спрайт перемещается, загружается или когда добавляется родитель.
  3. Твердая ли математика? Должен ли я подходить к этому по-другому?
  4. Можно ли это сделать лучше, и не могли бы вы привести примеры?

person ShadowScripter    schedule 04.03.2012    source источник


Ответы (1)


Обрезать RECT намного проще, чем это:

clipped_rect.left= MAX(rect_a.left, rect_b.left);
clipped_rect.right= MIN(rect_a.right, rect_b.right);
clipped_rect.top= MIN(rect_a.top, rect_b.top);
clipped_rect.bottom= MAX(rect_a.bottom, rect_b.bottom);

bool completely_clipped= 
    clipped_rect.left>=clipped_rect.right || 
    clipped_rect.bottom>=clipped_rect.top

Это предполагает, что Y увеличивается по мере того, как вы идете вверх. Должно быть довольно легко найти производительную версию MIN и MAX для конкретной платформы.

person MSN    schedule 04.03.2012
comment
Ах да, забыл отметить как ответ. Забыл сказать, что ваш ответ сработал настолько намного лучше, с небольшим изменением порядка min и max. Очень признателен! - person ShadowScripter; 04.04.2012