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

Загрузка и вывод изображения в формате .bmp на экран
Загрузка и вывод изображения в формате .bmp на экран

Содержание статьи:

1. Введение;
2. Особенности Linux и WindowsCE;
3. Компиляция примера;
4. Заключение.

1. Введение
Продолжим изучение кросс-платформенной графической библиотеки SDL в Linux. Для компиляции исходников статьи нужно настроить компиляторы, как описано здесь. Сегодня научимся загружать bitmap’ы – графические файлы с расширением .bmp. Почему не gif, или tga, спросите Вы – они же значительно меньше «весят»? Все верно, но SDL без библиотеки-расширения SDL_Image поддерживает только загрузку .bmp-файлов. Со временем научимся грузить и их =)

2. Особенности WindowsCE
Для загрузки в системах Windows и Linux, если графический файл picture.bmp поместить в папку с исполняемым файлом, достаточно такого кода:

SDL_Surface *loaded_picture=NULL;//поверхность SDL для загружаемой картинки
…инициализация SDL...
loaded_picture= SDL_LoadBMP("picture.bmp”);//сама загрузка


Этот код в WinCE, к сожалению, ничего не загрузит. А все из-за того, что в WinCE отсутствует понятие текущей директории, там для загрузки картинки в общем случае требуется указать полный путь. Допустим, если файл picture.bmp размещен в корне карты памяти:

loaded_picture= SDL_LoadBMP("Storage Card/picture.bmp”);//простая загрузка в wince

Так-же полный путь, указанный для загрузки в программе для Linux поможет избежать неуверенной загрузки картинки при запуске программы из GUI-файловых менеджеров (konqueror, dolphin и др.), которые не всегда корректно обозначают текущую директорию.
Это не прибавляет удобства как для кросс-компиляции, так и для готовой программы. Ведь мы не знаем заранее в какой папке пользователь разместит екзешник и ресурсы. А просить его сделать это в заранее заданном месте как-то не солидно =).
Тут можно попробовать узнать из какой папки был запущен исполняемый файл, и в зависимости от этого настроить загрузку нашей картинки. Создайте чистую папку для нового микропроекта. В ней создайте файл main.cpp. Для ресурсов в ней же создайте дополнительную папку res и в нее поместите небольшой файл picture.bmp.(ссылка на готовый проект в конце статьи – можете взять оттуда). Пишем в нашем main.cpp:

//Подключаем заголовочные файлы
#include <cstdio>//для printf
#include "SDL.h"
#include <cstring>//для работы со строками: strcpy и strcat

//Определим подстановки - символические константы
#define MAX_PATH_LENGTH 128 //максимальное кол-во символов пути исполняемого файла
#define RESOURCE_PATH "res/" //директория ресурсов программы
#define PICTURE "picture.bmp" //название файла картинки


Как Вы знаете, подстановки при компиляции будут заменены их значениями. Например, на место PICTURE будет подставлено "picture.bmp”. Это сделано для удобства, теперь, чтобы изменить путь к ресурсам программы или название загружаемого файла не нужно отыскивать все их вхождения в исходник. Достаточно изменить только одну строку в начале программы. Далее:

//Глобальные константы и переменные
const int SCREEN_WIDTH= 240;
const int SCREEN_HEIGHT= 320;
const int SCREEN_BPP= 16;
const char resource_name[]= RESOURCE_PATH;//создаем массив символов с путем от экзешника до ресурсов "res”
const char pict_name[]= PICTURE;//имя .bmp-файла
Uint32 back_color;//Этим цветом буду закрашивать экран
SDL_Surface *screen= NULL;//Основная поверхность SDL
SDL_Surface *loaded_picture=NULL;//поверхность SDL для загружаемой картинки

Выше мы задали две строки – два символьных массива: resource_name и pict_name, оканчивающихся нуль-терминатором. О работе со строками в С/С++ можно прочитать хотя бы здесь, или здесь.

Далее, используя нулевой аргумент функции main посмотрим, что передает ей каждая из наших операционных систем:

linux (console, mc): ./prog_name
linux (файловые менеджеры с GUI): /home/proj/prog_name
win32: D:\proj\prog_name.exe
wince: \Storage Card\proj\prog_name.exe
а получить мы в итоге хотим:
linux (console, mc): ./res/picture.bmp
linux (файловые менеджеры с GUI): /home/proj/res/picture.bmp
win32: /res/picture.bmp
wince: /Storage Card/proj/res/picture.bmp

Рассмотим код далее:

////////////////////////////////////////////////
// ГЛАВНАЯ ФУНКЦИЯ ПРОГРАММЫ //
////////////////////////////////////////////////

int main( int argc, char* args[] )
{

  char res_path[MAX_PATH_LENGTH];//Путь запуска файла
  res_path[0] = '\000';//пока стринг пуст
  strcpy(res_path, args[0]);//скопировали полный путь запуска в res_path

  printf("from OS=%s\n", res_path);

  if (res_path[0]!='.')//Если вызов не из консоли linux или mc, то...
  {
  //Перевернем обратные слэши Windows
  for (unsigned int i= 0 ;i!= (strlen(res_path)-1); ++i)//работаем по длине стринга
  {
  if (res_path[i]=='\\') res_path[i]='/';//если нашли \, заменяем на /
  }
  }

  //отсечем имя программы справа до первого слэша - просто заполним нулями
  for (int i= (strlen(res_path)-1);(res_path[i] !='/') && (i>=0); --i) res_path[i]='\000';

#ifndef UNDER_CE//Если это не wince
#ifdef _WIN32//И это 32-разрядная windows
  res_path[0]='\000';//то очистим путь во избежание проблем с кирилицей в папках Windows
#endif
#endif


Здесь мы получаем в массив символов res_path нулевой аргумент, переданный ОС нашей функции main — путь ее запуска. Что, собственно и распечатывается в строке printf("from OS=%s\n", res_path);.Забыл сказать, что увидеть консольный вывод в WindowsCE штатными средствами нельзя — их просто нет =). Зато есть программа PocketConsole v1.3 (http://pixelcode.ucoz.ru/J3d1/C-Articles/Article2_ldbmp/poccon13.tar.gz) (пользователи WinMobile5 не забудьте подправить реестр — там написано как и что сделать. Она автоматически запускается для приложений с консольным выводом. Не спрашивайте как она это делает — я не знаю, но она работает=). 
Далее, для вызова из консоли или mc просто отсекаем имя программы, для всех отальных ОС «переворачиваем» слэши Windows. Именно так — слэши для Linux и компиляторов семейства GCC должны быть прямыми, а не обратными как в семействе Windows (нужно переворачивать). В конце манипуляций отсекаем имя программы — оно нам не нужно.
Еще один момент: чтобы избежать проблем с русскоязычными названиями в пути «большой» Windows (с CE, как ни странно все нормально), будем грузиться в ней только по относительному пути. Т.е. Для нее res_path очищаем.

В коде выше применена условная компиляция для задания кода только для «большой» Windows:

#ifndef UNDER_CE//Если это не wince
#ifdef _WIN32//И это 32-разрядная windows
  res_path[0]='\000';//то очистим путь во избежание проблем с кирилицей в папках Windows
#endif
#endif


  Аналогично можно иcпользовать #ifdef linux и #ifdef _WIN32 (соответственно только для Linux и всех 32-битных Windows, включая WinCE). Только в конце блоков условной компиляции не забывайте #endif.
  Итак в переменной (хотя это массив) res_path получили ./ или полный путь до исплняемого файла для linux, пустой стринг для win32 и путь к исполяемому файлу для wince. Добавим res/ имя папки с ресурсами и имя нашей картинки picture.bmp:

  strcat(res_path, resource_name);//добавим наименование каталога ресурсов
  strcat(res_path, pict_name);//добавим имя файла-картинки
  printf("loading path=%s \n", res_path);


  Оператор printf... и здесь позволит нам проконтролировать то ли мы получаем в итоге, что нужно.
Ок. Теперь в res_path все готово для загрузки. Инициализируем SDL и грузим:

//Start SDL
  printf("SDL initialization...\n");
  if (SDL_Init(SDL_INIT_VIDEO)== -1)
  {
  printf("SDL initializing failure!\n");
  return 1;
  }
  else printf("SDL initializing -- Ok\n");

  //Set up the screen
#ifdef UNDER_CE// Под WinCE используем полноэкранное окно, исп. основную память и абсолютный путь файлов
  screen= SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE | SDL_FULLSCREEN);
#else //Под Win32 и Linux используем стандартное окно и память видеокарты для размещения поверхностей SDL
  screen= SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_HWSURFACE);
#endif

//If there was an error in setting up the screen
  if (screen== NULL)
  {
  printf("Unable to SetVideoMode\n");
  return 1;
  }
  else printf("VideoMode settings -- Ok\n");

  //очистим экран черным цветом
  SDL_LockSurface(screen);
  back_color= SDL_MapRGB(screen->format, 0, 0, 0); //получили back_color в формате screen
  SDL_FillRect (screen, NULL, back_color);
  SDL_UnlockSurface(screen);
  SDL_Flip (screen);

  //загрузим картинку из найденного ранее пути res_path
  loaded_picture= SDL_LoadBMP(res_path);
  SDL_BlitSurface(loaded_picture, NULL, screen, NULL);//отобразим ее
  SDL_Flip (screen);

  SDL_Delay(4000);// Задержка перед выходом чтобы увидеть результат работы программы

  //удалим поверхности SDL перед выходом
  printf("SDL quiting...\n");
  SDL_FreeSurface(loaded_picture);
  SDL_FreeSurface(screen);
  SDL_Quit();

  return 0;
}


Теперь файл main.cpp сохраним, скомпилируем под linux при помощи Makefile из первой статьи. Запустим. Работает? Если нет, то проверьте, рядом с Вашим исходником должна быть папка с именем res, а в ней должна лежать картинка picture.bmp.
  Получилось? Отлично! Попробуйте сами скомпилировать так же под win32 и wince.

Финальный исходный код (файл main.cpp)
//Подключаем заголовочные файлы
#include <cstdio>//для printf
#include "SDL.h"
#include <cstring>//для работы со строками: strcpy и strcat

//Определим подстановки
#define MAX_PATH_LENGTH 128 //максимальное кол-во символов пути до исполняемого файла
#define RESOURCE_PATH "res/" //директория ресурсов программы
#define PICTURE "picture.bmp" //название файла картинки

//Глобальные константы и переменные
const int SCREEN_WIDTH= 240;
const int SCREEN_HEIGHT= 320;
const int SCREEN_BPP= 16;
const char resource_name[]= RESOURCE_PATH;
const char pict_name[]= PICTURE;
Uint32 back_color;//Этим цветом буду закрашивать экран
SDL_Surface *screen= NULL;//Основная поверхность SDL
SDL_Surface *loaded_picture=NULL;//поверхность SDL для загружаемой картинки


////////////////////////////////////////////////
// ГЛАВНАЯ ФУНКЦИЯ ПРОГРАММЫ //
////////////////////////////////////////////////

int main( int argc, char* args[] )
{

  char res_path[MAX_PATH_LENGTH];//Путь запуска файла
  res_path[0] = '\000';//Для ОС кроме wince используем текущую директорию

#ifdef UNDER_CE// под wince нужен путь запуска
  strcpy(res_path, args[0]);//скопировали полный путь запуска в res_path
  printf("%s\n", res_path);
  for (int i= 0 ;i!= MAX_PATH_LENGTH-1; ++i)// Перевернем обрантые слэши wince
  {
  if (res_path[i]=='\\') res_path[i]='/';//если нашли \, заменяем на /
  }
  for (int i= MAX_PATH_LENGTH-1;(res_path[i] !='/') && (i>=0); --i) res_path[i]='\000';//Отсечем имя.exe
#endif// закончили блок условной компиляции для wince

  strcat(res_path, resource_name);//добавим наименование каталога ресурсов
  strcat(res_path, pict_name);//добавим имя файла-картинки
  printf("loading path=%s \n", res_path);

  printf("%d\n", strlen(resource_name));

  //Start SDL
  printf("SDL initialization...\n");
  if (SDL_Init(SDL_INIT_VIDEO)== -1)
  {
  printf("SDL initializing failure!\n");
  return 1;
  }
  else printf("SDL initializing -- Ok\n");

  //Set up the screen
#ifdef UNDER_CE// Под WinCE используем полноэкранное окно, исп. основную память и абсолютный путь файлов
  screen= SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE | SDL_FULLSCREEN);
#else //Под Win32 и Linux используем стандартное окно и память видеокарты для размещения поверхностей SDL
  screen= SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_HWSURFACE);
#endif

//If there was an error in setting up the screen
  if (screen== NULL)
  {
  printf("Unable to SetVideoMode\n");
  return 1;
  }
  else printf("VideoMode settings -- Ok\n");

  //очистим экран черным цветом
  SDL_LockSurface(screen);
  back_color= SDL_MapRGB(screen->format, 0, 0, 0); //получили back_color в формате screen
  SDL_FillRect (screen, NULL, back_color);
  SDL_UnlockSurface(screen);
  SDL_Flip (screen);

  //загрузим картинку из найденного ранее пути res_path
  loaded_picture= SDL_LoadBMP(res_path);
  SDL_BlitSurface(loaded_picture, NULL, screen, NULL);
  SDL_Flip (screen);

  SDL_Delay(4000);// Задержка перед выходом чтобы увидеть результат работы программы

  //удалим поверхности SDL перед выходом
  printf("SDL quiting...\n");
  SDL_FreeSurface(loaded_picture);
  SDL_FreeSurface(screen);
  SDL_Quit();

  return 0;
}


Теперь файл main.cpp сохраним, скомпилируем под linux при помощи Makefile из первой статьи. Запустим. Работает? Если нет, то проверьте, рядом с Вашим исходником должна быть папка с именем res, а в ней должна лежать картинка picture.bmp.
Получилось? Отлично! Попробуйте сами скомпилировать так же под win32 и wince.
P.S.: Исходный файл, Makefile, picture.bmp и готовые исполняемые файлы для 3-х платформ можно скачать здесь(http://pixelcode.ucoz.ru/J3d1/C-Articles/Article2_ldbmp/a2_source.tar.gz). Примечание: там-же лежит SDL.dll для запуска в win32 или в Wine.
Если что-то не получается – пишите J3d1 (j3d1adm1n@yandex.ru)

Литература:
(1)
http://www.rsdn.ru/article/cpp/cstr.xml
(2)
http://gazette.linux.ru.net/lg76/articles/rus-rogers.html


Категория: SDL | Добавил: dimanche13 (09.01.2010) | Автор: J3d1
Просмотров: 7814 | Комментарии: 1 | Рейтинг: 0.0/0 |
Всего комментариев: 0
Имя *:
Email *:
Код *:
Copyright MyCorp © 2025