Среда, 15.05.2024, 07:00
Personal dimanche13 site
Главная | Регистрация | Вход Приветствую Вас Гость | RSS
Категории каталога
Мои статьи [22]
BlitzMax [17]
раздел содержит статьи относящиеся к языку программирования BlitzMax
SDL [9]
раздел содержит статьи на тему SDL
Code::Blocks [3]
в этом разделе рассказывается как прикрутить движок к интегрированной среде разработки(IDE) Code::Blocks
Форма входа
Поиск
Друзья сайта
Главная » Статьи » SDL

Основы SDL(часть№3 поверхности)
Привет, друзья! Я снова с Вами :) На этот раз продолжение тутора по основам СДЛ. На этот раз пришло время разобраться поподробнее с поверхностями, еще их называют сЮрфейсами, сУрфейсами, сАрфейсами, и по-другому, как и кому на душу положит, это вопрос семантики. Но как ты их не зови, а все они указывают на одну и ту же структуру SDL_Surface Примерно так она выглядит в исходниках СДЛ, некоторые поля не указаны, так как нам они не понадобятся.
 
typedef struct SDL_Surface {
      Uint32 flags; /* Read-only */
      SDL_PixelFormat *format; /* Read-only */
      int w, h; /* Read-only */
      Uint16 pitch; /* Read-only */
      void *pixels; /* Read-write */
      SDL_Rect clip_rect; /* Read-only */
      int refcount; /* Read-mostly */
} SDL_Surface;
 
Ну-ка вспоминайте, где мы получили нашу первую сурфейс для СДЛ? Правильно, это была сурфейс экрана. Мы получали ее функцией SDL_SetVideoMode, затем мы получали сурфейс для текста, функцией………… .
Эти две функции возвращали нам сурфейсы, для разных действий с ними, но при этом они были одного формата. Несколько перефразируя родной хелп от СДЛ, SDL_Surface - представляет собой, часть графической памяти, которая может быть нарисована. Как вы можете видеть, структура состоит из нескольких полей. Давайте посмотрим, что каждое из них обозначает:
w,h – Это ширина и высота поверхности в пикселях.
Flags – ну это вы и без меня помните. УТОЧНИТЬ !!!
Pitch – это ширина поверхности в байтах
clip_rect – прямоугольник отсечения. То что в этот прямоугольник, не попадает, рисоваться не будет. Имеет тип SDL_Rect, мы с Вами его уже изучали, в предыдущий статье.
refcount – счетчик ссылок на поверхность, далее будет поподробнее. 
pixels – указатель на массив данных поверхности, то есть на кучу пикселей размером w*h. Почему этот массив типа void? Потому что за ранее неизвестно, каким образом там представлен пиксель. Одним ли байтом, двумя ли, тремя или четырьмя. Тогда, вы вероятно спросите, а как же нам это узнать. Узнать это можно изучив поле *format.
Давайте сначала напомню вам вот что: Пиксель – это, как вы знаете, минимальная часть изображения, Если экранная поверхность, к примеру, имеет размеры 640х480 пикселей, значит, отображаться будут 307200 пикселей. Но, как я уже упомянул ранее, из этого вовсе не следует, что этот массив данных(*pixels) будет занимать 307200 байтов, потому что, пиксель может быть представлен как одним байтом, так и двумя, тремя или даже четырьмя байтами. Тогда если пиксель представляется, скажем 4-мя байтами, размер *pixels будет уже 307200 * 4 = 1228800, это уже больше Мегабайта. Подытоживая можно выразиться кратко, что размер массива пикселей зависит от размера одного пикселя в байтах.
Итак, выяснили, что нам определенно надо знать, как представлены пиксели в нашем сюрфейсе. И о, чудо! как же я люблю «говорящие названия» функций, методов и классов SDL_PixelFormat – содержит как раз всю необходимую информацию о формате пикселей нашей поверхности. Через указатель *format мы можем получить данные, которые нам так нужны. Сама же структура выглядит так:
 
typedef struct {
     SDL_Palette *palette;
     Uint8 BitsPerPixel;
     Uint8 BytesPerPixel;
     Uint8 Rloss, Gloss, Bloss, Aloss;
     Uint8 Rshift, Gshift, Bshift, Ashift;
     Uint32 Rmask, Gmask, Bmask, Amask;
     Uint32 colorkey;
     Uint8 alpha;
} SDL_PixelFormat;
 
alpha – общая прозрачность поверхности.
colorkey – прозрачный цвет для данной поверхности, так называемый цвет-маска
BitsPerPixel – сколько бит отводится на представление одного пикселя
BytesPerPixel – сколько байт на представление одного пикселя, 1,2,3 или 4, от этого зависит каков размер *pixels и, соответственно, зависит как найти нужный пиксель, в этом массиве. Полезно для, тех кто желает работать на прямую с картинкой, иными словами получать доступ на запись/считывание пикселей в сюрфейсе.
Rshift, Gshift, Bshift, Ashift – сдвиг до цвета(R,G,B) или прозрачности(A) в цвете
Rmask, Gmask, Bmask, Amask – двоичная маска для определения, где и как шифруется цвет
Rloss, Gloss, Bloss, Aloss – показывает сколько пикселей «потеряно» при упаковке цвета в слово Поля эти нужны для того, чтобы узнать как кодируются информация о конкретном цвете. Ведь если цвет запакован в, допустим 4 байта, то он не обязательно должен быть стандартным RGBA, может быть специфически зашифрован как AGBR или вообще, на разные цветовые компоненты будет отводиться разное количество бит.
Ну a чтобы вас не путать, значения этих полей, проще всего продемонстрировать на примере, как изымается красная компонента из зашифрованного цвета:
 
/* Extracting color components from a 32-bit color value */ SDL_PixelFormat *fmt;
SDL_Surface *surface;
Uint32 temp, pixel;
Uint8 red;
 
fmt = surface->format; // берем поле формата пикселя SDL_LockSurface(surface); pixel = *((Uint32*)surface->pixels); // берем первый пиксель поверхности, приводя его принудительно к 4 байтам SDL_UnlockSurface(surface); /* берем красную компоненту */ temp =
 
pixel & fmt->Rmask; /* Isolate red component */
temp = temp >> fmt->Rshift; /* Shift it down to 8-bit */
temp = temp << fmt->Rloss; /* Expand to a full 8-bit number */
red = (Uint8)temp;
 
    Не пугайтесь, не надо так делать каждый раз, когда вам надо узнать компоненту цвета. Для этого в СДЛ есть специальные функции, которые возвратят вам, все что необходимо, учитывая все детали, в том числе и формат пикселей в сюрфейсе.
    Еще одной тонкостью приведенного выше кода, на которую следует обратить внимание, является то, что получить доступ к массиву пикселей на считывание/запись можно только после блокировки поверхности функцией SDL_LockSurface. После проведения необходимых манипуляций, сюрфейс следует «освободить» SDL_UnlockSurface. Запомните это.
     Если раньше вы пытались изучать СДЛ, то наверное помните как монстрообразно выглядели такие простые и обыденные казалось бы функции как: нарисовать пиксель(putpixel) на экране или узнать его цвет(getpixel). Теперь вооруженные новыми знаниями вы, глядя на них, поймете, как это реализуется и почему это делается именно так.
 
     Итак последнее поле этого класса *Pallete. *Palette – палитра, заполняется в том случае, если цвет кодируется одним байтом. Как в старые добрые времена VGA-графики, где была таблица, называемая палитра (не путать с пол-литра, алкаши) она содержала в себе 256 комбинаций цветов, больше просто не проиндексируешь одним байтом (2^8).
     Выглядит структура палитры элементарно:
 
typedef struct{
   int ncolors;
   SDL_Color *colors;
} SDL_Palette;
 
ncolors – количество цветов заполненных/используемых в палитре *colors – это массив цветов SDL_Color(которую мы уже изучали) Если вы используете 8 битный цвет, у вас есть палитра, то доступ к цвету в палитре можно получить так:
 
SDL_Color *color;
 
/* Lock the surface */
SDL_LockSurface(surface); index=*(Uint8 *)surface->pixels; // берем первый(левый-верхний)
 
color=surface->format->palette->colors[index];
 
/* Unlock the surface */
SDL_UnlockSurface(surface);
 
printf("Pixel Color-> Red: %d, Green: %d, Blue: %d. Index: %d\n", color->r, color->g, color->b, index);
 
Надеюсь, вас не очень пугает такая громоздкая запись
  
   color = surface->format->palette->colors[n];
 
Это потому, что все эти данные можно получить, обращаясь к указателю, на структуру в структуре и еще в структуре, иными словами получается некая матрешка из классов, вложенных друг в друга и так, чтобы достать самую маленькую матрешечку, приходится начинать с самой большой, самой первой, постепенно продвигаясь к нужной. Картинка Вообще в этом нет никаких усложнений записи, потому как все предельно понятно из названия полей, методов и классов, что в принципе учит и нас самих избегать корявых названий для переменных в собственной программе. Так переводя на русский, кусок кода выше, получим:
 
это_цвет = поверхность->формат_пикселя->палитра->цвет[нужный_нам];
 
Ну ладно, это я уже слишком отвлекся, да еще и на темы, мало относящиеся к теме нашего повествования. А пока предлагаю поэкспериментировать с поверхностью экрана. Этот сюрфейс создается с помощью функции SDL_SetVideoMode().
    Возьмем самый простой код, создающий нам экранную поверхность и посмотрим, что там получилось внутри поверхности, т.е. изучим эту SDL_Surface. Конечно, это будет зависеть от того какие мы дадим аргументы на вход SDL_SetVideoMode.
 
int main ( int argc, char** argv ) {
 
Проинициализируем видео подсистему СДЛ
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
 {
   printf( "Unable to init SDL: %s\n", SDL_GetError() ); return 1;
 }
 
// создадим поверхность экрана SDL_Surface *screen = SDL_SetVideoMode(640, 480, 16, SDL_HWSURFACE|SDL_DOUBLEBUF);
 
if ( !screen )
 {
   printf("Unable to set 640x480 video: %s\n", SDL_GetError());
   return 1;
 }
 
// изучаем созданную поверхность экрана
printf("screen->w: %d, screen->h: %d\n", screen->w, screen->h);
printf("screen->pitch: %d \n", screen->pitch);
printf("screen->flags: 0x%x \n", screen->flags);
printf("screen->clip_rect.x: %d, screen->clip_rect.y: %d\n", screen->clip_rect.x, screen->clip_rect.y);
printf("screen->clip_rect.w: %d, screen->clip_rect.h: %d\n", screen->clip_rect.w, screen->clip_rect.h);
return 0;
}
 
После выполнения программы, в папке с ехе-шником будет лежать файл stdout.txt – это файл стандартного вывода, куда пишутся все printf. Я получил следующее содержание:
 
screen->w: 640, screen->h: 480
screen->pitch: 1280
screen->flags: 0x20000000
screen->clip_rect.x: 0, screen->clip_rect.y: 0
screen->clip_rect.w: 640, screen->clip_rect.h: 480
 
   Размеры поверхности в точности такие какие мы и задали при создании( а могло ли быть иначе?) Соответственно и прямоугольник отсечения тоже соответствует этим размерам, так как по умолчанию он соответствует размерам поверхности. Флаги, какие задали такие и видим, только в 16-тиричном виде, так удобнее.
   Кстати, пока недалеко ушли, размеры отсекающего прямоугольника (SDL_Rect clip_rect;) можно так же узнать функцией SDL_GetClipRect() она принимает в себя 2 параметра, исследуемую сурфейс и прямоугольник - приемник данных. В коде это будет выглядеть, примерно так:
 
SDL_Rect *clip = new SDL_Rect; // прямоугольник для данных SDL_GetClipRect(screen, clip); // изучаем прямоугольник отсечения эрана(screen) printf("clip->w: %d, clip->h: %d\n", clip->w, clip->h); // выводим в станд. вывод
 
Функция, которая устанавливает отсекающий прямоугольник SDL_SetClipRect и так же принимает в себя 2 параметра. Сурфейс и прямоугольник.
void SDL_SetClipRect(SDL_Surface *surface, SDL_Rect *rect);
Если второй параметр NULL, то ограничивающий прямоугольник будет иметь размеры сюрфейса, иными словами он ничего ограничивать не будет. В общем, не вижу пользы запускать эту функцию с параметром rect = NULL. J Если вы хотите узнать сколько байт или бит в созданной поверхности отводится на пиксель, то пожалуйста:
 
printf("\tSDL_PixelFormat \n");
printf("screen->format->BitsPerPixel: %d \n", screen->format->BitsPerPixel);
printf("screen->format->BytesPerPixel: %d \n", screen->format->BytesPerPixel);
 
    Теперь вы достаточно подкованы теоретически, чтобы на практике узнавать все о сюрфейсах. Можете к примеру, поэкспериментировать с поверхностями для текста, которые мы создавали не так давно. Поверьте, это увлекательное занятие на досуге, по крайней мере, всё лучше, чем трескать ханку в подъезде. :) Вот в общем-то и все, о чем я хотел рассказать в этом туторе… А нет, погодите-ка ведь еще осталось не изученным поле refcount в структуре SDL_Surface.
    Но об этом давайте уже в другой раз. С новыми, так сказать, силами. А пока, я надеюсь, что этот урок сделал вас хоть чуть-чуть лучше и светлее, ну в смысле, просвещеннее в СДЛ вобщем и в поверхностях в частности.
    До будущих встреч, друзья. Чао!
Категория: SDL | Добавил: dimanche13 (15.01.2010) | Автор: dimanche13
Просмотров: 4815 | Комментарии: 1 | Рейтинг: 3.0/1 |
Всего комментариев: 1
1 J3d1  
0
Спасибо! Полезная статья, я не встречал чтобы описывалось так подробно и полно. Без знания основ-никуда.

Имя *:
Email *:
Код *:
Copyright MyCorp © 2024