Программа для построения трехмерных графиков со странным поведением по пикселям [Более быстрое рисование путем перетаскивания окна]

Итак, я написал простую программу для построения трехмерных графиков на C ++ с использованием библиотек Allegro 4. Я сделал это самым простым способом, нарисовав пиксель за пикселем. Обычно отображение отдельных пикселей на экране происходит довольно медленно из-за того, как работает Allegro, и чтобы построить график в разрешении 640x480, мне нужно подождать минуту или две.

Итак, я рендерил изображение для моего друга, чтобы показать, и поэтому я перетаскивал окна, чтобы сделать хороший снимок экрана, и я обнаружил, что перетаскивание окна с изображением рендеринга значительно ускоряется, пока я держу окно. С 2 минут рисует все за 10 секунд.

В чем причина такого странного поведения? Это что-то связано с окнами Windows или вызвано самим Allegro? Есть ли этому объяснение?

Снимок экрана

Также мой код

#include <allegro.h>
#include <iostream>
#include <math.h>

using namespace std;

float MAX_Z = 1;
float MIN_Z =-1;
float SCALE =50;

inline void init(unsigned int width, unsigned int height)
{
    allegro_init();
    set_color_depth(24);
    set_gfx_mode(GFX_AUTODETECT_WINDOWED, width, height, 0, 0);

    install_timer();
    install_keyboard();
    install_mouse();
}

inline void deinit()
{
    clear_keybuf();
    allegro_exit();
}

int get_z_color (float z)
{
    if (z >= 0)
    {
        return makecol(255, (z/MAX_Z)*255, (z/MAX_Z)*255);
    }
    else
    {
        return makecol(255 - (z/MIN_Z)*255,0, 0);
    }
}

float get_z (float x, float y)
{
    return sin(sqrt(pow(x,2)+pow(y,2)));
}

float int_to_float (int a)
{
    return a;
}

int main()
{
    unsigned int res_width, res_height;

    cout << "Window size (W,H): ";
    cin >> res_width >> res_height;
    cout << endl << "Initiating in " << res_width << "x" << res_height << " resolution..." << endl;

    init(res_width,res_height);

    cout << "Success! Drawing graph..." << endl;

    for (int y=0; y<res_height; y++)
    {
        for (int x=0; x<res_width; x++)
        {
            float valued_x = (int_to_float(x)-(int_to_float(res_width)/2))/SCALE;
            float valued_y = (int_to_float(-y)+(int_to_float(res_height)/2))/SCALE;
            _putpixel24(screen,x,y,get_z_color(get_z(valued_x,valued_y)));
            //cout << "Drawing (" << valued_x << "," << valued_y << ")" << endl;
        }
    }

    cout << "Graph drawn." << endl;

    cin >> new char;

    cout << "Closing...";

    deinit();
    return 0;
}
END_OF_MAIN()

person Cathier    schedule 27.01.2016    source источник
comment
Вероятно, имеет какое-то отношение к Windows DWM.   -  person Mark Ransom    schedule 28.01.2016


Ответы (1)


Рисование на поверхности экрана, какую бы библиотеку вы ни использовали, всегда требует больших затрат.

Я никогда не использовал Allegro (я использую SDL), но я предполагаю, что окна перерисовывают поверхность экрана каждый раз, когда на него помещается один пиксель, и, перетаскивая окна, вы предотвращаете фактическое перерисовку.

Если вы хотите, чтобы ваша программа резко увеличила производительность, вы всегда должны рисовать за пределами экрана и переносить всю поверхность на поверхность экрана после завершения рисования (это базовая техника двойной буферизации).

Как я уже сказал, я никогда не использовал Allegro, но, насколько я понял, вы можете сделать что-то вроде этого:

int main()
{
  unsigned int res_width, res_height;

  cout << "Window size (W,H): ";
  cin >> res_width >> res_height;
  cout << endl << "Initiating in " << res_width << "x" << res_height << " resolution..." << endl;

  init(res_width,res_height);

  BITMAP *temporaryBitmap = create_bitmap(res_width, res_height);

  cout << "Success! Drawing graph..." << endl;

  for (int y=0; y<res_height; y++)
  {
    for (int x=0; x<res_width; x++)
    {
        float valued_x = (int_to_float(x)-(int_to_float(res_width)/2))/SCALE;
        float valued_y = (int_to_float(-y)+(int_to_float(res_height)/2))/SCALE;
        _putpixel24(temporaryBitmap,x,y,get_z_color(get_z(valued_x,valued_y)));
        //cout << "Drawing (" << valued_x << "," << valued_y << ")" << endl;
    }
  }

  blit(temporaryBitmap, screen, 0, 0, 0, 0, temporaryBitmap->w, temporaryBitmap->h);

  cout << "Graph drawn." << endl;

  cin >> new char;

  cout << "Closing...";

  destroy_bitmap(temporaryBitmap);

  deinit();
  return 0;
}
person Martin Véronneau    schedule 27.01.2016
comment
Меня больше интересовало, ПОЧЕМУ это происходит, а не как это делать. Но сейчас я фактически включил в свой код двойную буферизацию, и я удивлен, как на мгновение она все прорисовала. - person Cathier; 28.01.2016
comment
Как я уже сказал, Windows перестает обрабатывать сообщения перерисовки, когда окно перетаскивается, поэтому поверхность вашего экрана фактически становится своего рода внеэкранной поверхностью, что автоматически ускоряет процесс. - person Martin Véronneau; 28.01.2016