Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  

Название темы: Игра Ксоникс
Показать сообщение отдельно
pva pva вне форума

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Цитата Doom77:
не могли бы вы упростить код »
только если подняться на высокий уровень (С++).
Добавил комментариев
Код: Выделить весь код
// это чтобы можно было легко подменить тип-носитель
// для "цвета" ячейки
typedef int surf_bit_t;

struct rect_t
{
    // прямоугольник - понадобится для пересечений
   int left, top, right, bottom;
}

// стркуктура, которая указывает, в каком виде хранится картинка.
// данные хранятся в виде линейного массива определённой ширины строчки
//                     на картинке нарисован массив, у которого stride = 6,
//     x x x x x x     width = 4, height = 3. Можно сказать, что мы работаем
//     x x 1 1 1 1                   с большим массивом 6x5, а можно что с
//     x x 1 0 0 0     1 1 1 1 ? ?   маленьким 4x3, строчки которого
//     x x 1 0 0 0     1 0 0 0 ? ?   расположены через 6 элементов.
//     x x x x x x     1 0 0 0 ? ?   begin в последнем случае указывает на
//                                   начало "маленького" массива.

struct surface_desc
{
  surf_bit_t *begin; // начало данных
  unsigned width, height, stride; // длина, ширина блока, длина строчки
};

void __blt(surface_desc* from, surface_desc* to)
{
    // функция НЕ ПОЗВОЛЯЕТ копировать в себя, то есть когда from и to могут пересекаться.
    // копирование без проверки исходых данных.
    // чтобы случайно не попортить память при записи, руководствуемся размерами конечной области

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

    // row_first1 пробегает строчки, куда копировать, от начала до конца, с шагом stride
    // row_last1 - это и есть конец (посчитали и запомнили)
    // row_first1 пробегает строчки, откуда копировать, с шагом stride

    for(surf_bit_t *row_first1=to->begin,
       *row_last1=to->begin+from->stride*to->width,
       *row_first2=from->from->begin;
        row_first1<row_last1; row_first1+=to->stride, row_first2+=from->stride)
    {
        // закомментирован пример кода для копирования,
        // можешь поиграться с ним (переделать в закрашивание)

        for(unsigned col=0; col<to->width; ++col)
        {
            // копирование
            row_first1[col] = row_first2[col];

            // а это могло бы быть закрашивание
            // row_first1[col] = 2;
        }

        // простейший случай - просто копирование памяти. Сэкономил код функцией
        //   memcpy(row_first2, row_first1, to->width*sizeof(surf_bit_t));
    }
}

inline int __constraint(int x, int min, int max)
{
    // ограничивает значение x - прибмвает к одному из порогов.
    // нужно для пересечения прямоугольников
   return x < min ? min : (x < max ? x : max);
}

//                                          функция, которая вычисляет аргументы для __blt
//     x x x x x x                          по заданным исходному прямоугольнику и конечной
//     x x 1 1 1 1        y 1 1 1 1 y y     точке, куда содержимое этого прямоугольника
//     x x 1 0 0 0  ->    y 1 0 0 0 y y     скопировать.
//     x x 1 0 0 0        y 1 0 0 0 y y     Надо учесть случаи, когда часть прямоугольника
//     x x x x x x                          будет выходить за пределы исходного или
//                                          конечного экранов. Для этого сделаем следующее:
// (1) пересчитаем координаты прямоугольников экранов в координатах исходного и конечного
// прямоугольника, (2) пересечём их с исходным и конечным прямоугольником. Затем (3)
// пересечём что получилось между собой. Получится прямоугольник (4), который и надо
// копировать. Пересчитаем его в координатах экранов (5), запишем в виде поверхностей (6) и
// отдадим функции __blt
//
//  (0,0)              (0,0)                  (0,0)
//    +---+ (w,0)        +---+ (w,0)            +---+ (w,0)
//    |   |              |   |                  |   |
//    |  x|x x x         |y y|y y y     ->      |  N|    область, которая_
//    |  x|x x x         |y y|y y y             |  N|    будет скопирована
//    +--x+x x x         +y-y+y y y             +--N+
// (0,h) x x x x      (0,h)                  (0,h)
//


void blt(surface_desc* from, /*поверхность-откуда*/
        int x, int y,  /*координаты, откуда копировать*/
        int width, int height,  /*размеры окошка*/
        surface_desc* to, /*поверхность-куда*/
        int to_x, int to_y) /*координаты куда*/
{
  // более удобный для пользователя интерфейс
  // с проверкой исходных данных
  // вычисляем перекрывающийся прямоугольник для копирования.

  surface_desc from1, to1;

  {
    // пересечение прямоугольника {0, 0, width, height} с
    // исходным изображением, в координатах копируемого окошка
    rect_t rect_src = {
        /*2*/__constraint(/*1*/-x, 0, width),
        /*2*/__constraint(/*1*/-y, 0, height),
        /*2*/__constraint(/*1*/from->width - x, 0, width),
        /*2*/__constraint(/*1*/from->height - y, 0, height)},
    // пересечение  {0, 0, width, height} с
    // конечным изображением и сразу с пересечённым исходным rect_src
        rect_dest = /*4*/{
        /*3*/__constraint(/*2*/__constraint(/*1*/-x_to, 0, width), rect_src.left, rect_src.right),
        /*3*/__constraint(/*2*/__constraint(/*1*/-y_to, 0, height), rect_src.top, rect_src.bottom),
        /*3*/__constraint(/*2*/__constraint(/*1*/to->width - x_to, 0, width), rect_src.left, rect_src.right),
        /*3*/__constraint(/*2*/__constraint(/*1*/to->height - y_to, 0, height), rect_src.top, rect_src.bottom)};

    // составляем полётное задание для __blt

    from1.begin  = /*6*/from->begin + (/*5*/rect_dest.top + y)*from->stride + /*5*/rect_dest.left + x;
    from1.stride = /*6*/from->stride; /*сохраняется для подобласти*/
    from1.width  = /*6*/rect_desc.right - rect_dest.left;
    from1.height = /*6*/rect_desc.bottom - rect_dest.top;

    to1.begin  = /*6*/to->begin + (/*5*/rect_dest.top + to_y)*from->stride + /*5*/rect_dest.left + to_x;
    to1.stride = /*6*/to->stride;     /*сохраняется для подобласти*/
    to1.width  = /*6*/rect_desc.right - rect_dest.left;
    to1.height = /*6*/rect_desc.bottom - rect_dest.top;
   }

   __blt(&from1, &to1);
}


// как пользоваться_
// где-то в программе выделена память под экран, сделано описание для этой памяти:

surf_bit_t screen1_bits[/*width*/320 * /*height*/200];
surface_desc screen1 = {/*begin*/ &screen1_bits, /*width*/320, /*height*/200, /*stride=width*/320};

surf_bit_t screen2_bits[/*width*/50 * /*height*/100];
surface_desc screen2 = {/*begin*/ &screen2_bits, /*width*/50, /*height*/100, /*stride=width*/50};

// в том месте, где надо скопировать делаем так:
// копируем прямоугольник 60x60 из точки (100,100) в (10,10) на другом экране
blt(&screen1, 100, 100, 60, 60, &screen2, 10, 10);

Отправлено: 12:03, 31-12-2008 | #4

Название темы: Игра Ксоникс