прогинг. Гущин_SDL. Аа нн
Скачать 1.04 Mb.
|
Примеры наложения поверхностей Примеры демонстрируют возможные комбинации состояний флагов SDL_SRCCOLORKEY, SDL_SRCALPHA, значений полей format→Amask, format→colorkey и format→alpha накладываемой и целевой поверхности и их влияние на результаты: #include #include #include #include #include /* Функция DrawFillRectByCentre заполняет на поверхности surf "цветом" color (возможно, с альфа-каналом) прямоугольник с центром в точке x, y, шириной 2*halfw+1 и высотой 2*halfh+1 пиксель. Если такой прямоугольник не умещается на поверхности - ничего не делая, возвращает -2. Если не удалось нарисовать, возвращает -1. Если все хорошо, возвращает 0. */ int DrawFillRectByCentre(SDL_Surface *surf, Uint16 x, Uint16 y, Sint16 halfw, Sint16 halfh, Uint32 color) { SDL_Rect dst; dst.x = x - halfw; dst.y = y - halfh; dst.w = 2*halfw+1; dst.h = 2*halfh+1; if( dst.x < 0 || dst.y < 0 || dst.w > surf->w || dst.h > surf->h) return -2; else return SDL_FillRect(surf, &dst, color); } typedef SDL_Surface* PSurface; int main(int argc, char *argv[]) { const int SN = 8; /* Количество нижних и верхних поверхностей: 3 двоичных признака => 2 в кубе */ SDL_Surface *screen; /* Указатель на поверхность окна */ SDL_Event event; SDL_Surface *upsurf[SN], /* Массивы указателей на верхние и */ *downsurf[SN]; /* нижние поверхности */ PSurface results[SN][SN]; /* Результаты */ Uint32 Rmask, Gmask, Bmask, Amask1, Amask2; Uint8 red, green, blue, alpha; SDL_Rect background; int i; setbuf(stderr, NULL); /* Отмена буферизации stderr для гарантированного сохранения сообщений об ошибках */ if (SDL_Init(SDL_INIT_VIDEO)) /* инициализация SDL */ { /* При ошибке формируем сообщение и выходим */ fprintf(stderr,"Ошибка в SDL_Init: %s\n",SDL_GetError()); return 1; 54 } /* После инициализации собственно SDL: */ screen=SDL_SetVideoMode(width, height, depth, SDL_ANYFORMAT); if (!screen) { fprintf(stderr,"SDL mode failed: %s\n",SDL_GetError()); SDL_Quit(); return 1; } Rmask = screen->format->Rmask; Gmask = screen->format->Gmask; Bmask = screen->format->Bmask; Amask1 = 0x00000000; Amask2 = 0xFF000000; for(i = 0; i < SN; i++) /* Обнуляем массивы указателей:*/ downsurf[i] = upsurf[i] = NULL; /* Создаем 8 поверхностей-подложек 81*81 пикселей, по значением бит в i (0 -- не будет, 1 -- будет): бит 0 (самый правый) -- будет ли установлен SDL_SRCCOLORKEY. Если будет, то компоненты colorkey имеют значения r,g,b = (65,65,65). Этим цветом рисуется горизонтальная полоса посередине. бит 1 -- будет ли установлен SDL_SRCALPHA. Если да, alpha = 65 бит 2 -- будет ли альфа-канал. Если будет, то вся поверхность непрозрачная, а вертикальная полоса посередине -- с прозрачностью 100.*/ for(i = 0; i < SN; i++) { Uint32 flags, key; SDL_Rect dst; flags = SDL_HWSURFACE; flags |= ((i & 1) ? SDL_SRCCOLORKEY : 0); flags |= ((i & 2) ? SDL_SRCALPHA : 0); downsurf[i]=SDL_CreateRGBSurface(flags, 81, 81, 32, Rmask, Gmask, Bmask, Amask2 * ((i & 4) == 4)); if(downsurf[i]) /* Проверка создания нижней поверхности */ { SDL_PixelFormat *fmt; fmt = downsurf[i]->format; if(i & 1)/* Установлен ли бит 0 ? (самый младший)*/ { if(i & 2) /* Установлен ли бит 1 ? (второй справа)*/ key = SDL_MapRGBA(fmt, 65,65,65,128); else key = SDL_MapRGB(fmt, 65,65,65); SDL_SetColorKey(downsurf[i], SDL_SRCCOLORKEY, key); } if(i & 2) /* Установлен ли бит 1 ? (второй справа)*/ SDL_SetAlpha(downsurf[i], SDL_SRCALPHA, 128); else /* Принудительно сбрасываем флаг SDL_SRCALPHA */ SDL_SetAlpha(downsurf[i], 0, 128); /* Создаем на поверхности равномерный голубой фон: */ DrawFillRectByCentre(downsurf[i], 40, 40, 40, 40, SDL_MapRGB(fmt, 0, 200, 200)); /* почти всю поверхность закрашиваем в непрозрачный ярко-красный цвет:*/ DrawFillRectByCentre(downsurf[i], 40, 40, 32, 32, SDL_MapRGB(fmt, 255, 0, 0)); /* Рисуем горизонтальную непрозрачную серую полосу */ DrawFillRectByCentre(downsurf[i], 40, 16 + 8, 32, 16, 55 SDL_MapRGB(fmt, 65, 65, 65)); /* Рисуем вертикальную полупрозрачную желтую полосу с прозрачностью 50%*/ DrawFillRectByCentre(downsurf[i], 16 + 8, 40, 16, 32, SDL_MapRGBA(fmt, 255, 255, 0, 128)); /* Рисуем светло-фиолетовую подложку на месте наложения:*/ background.x = 90 + 45 + i*90 - 40; background.y = 90; background.w = 81; background.h = 81; SDL_FillRect(screen, &background, SDL_MapRGB(screen->format, 255, 0, 255)); /* и ее же над ним:*/ background.x = 90 + 45 + i*90 - 40; background.y = 0; background.w = 81; background.h = 81; SDL_FillRect(screen, &background, SDL_MapRGB(screen->format, 255, 0, 255)); /* ..и накладываем поверхность на экран:*/ dst.x = 90 + 45 + i*90 - 40; dst.y = 90; dst.w = 81; dst.h = 81; SDL_BlitSurface(downsurf[i], NULL, screen, &dst); } } /* Создаем 8 поверхностей-для наложения 57*57 пикселя, по значением бит в i: бит 0 (самый правый) -- будет ли установлен SDL_SRCCOLORKEY?. Если будет, то компоненты colorkey имеют значения r,g,b = (200,200,200).Этим цветом рисуется горизонтальная полоса посередине. бит 1 -- будет ли установлен SDL_SRCALPHA. Если да, alpha = 100 бит 2 -- будет ли альфа-канал. Если будет, то вся поверхность непрозрачная и вертикальная полоса посередине с прозрачностью 200. */ for(i = 0; i < SN; i++) { Uint32 flags, key; SDL_Rect dst; flags = SDL_HWSURFACE; flags |= ((i & 1) ? SDL_SRCCOLORKEY : 0x00000000); flags |= ((i & 2) ? SDL_SRCALPHA : 0x00000000); upsurf[i]=SDL_CreateRGBSurface(flags, 57, 57, 32, Rmask, Gmask, Bmask, Amask2 * ((i & 4) == 4)); if(upsurf[i]) { SDL_PixelFormat *fmt; fmt = upsurf[i]->format; if(i & 1) /* Установлен ли бит 0 ? (самый младший)*/ { if(i & 2) /* Установлен ли бит 1 ? */ key = SDL_MapRGBA(fmt, 200,200,200,64); else key = SDL_MapRGB(fmt, 200,200,200); SDL_SetColorKey(upsurf[i], SDL_SRCCOLORKEY, key); } if(i & 2) /* Установлен ли бит 1 ? */ SDL_SetAlpha(upsurf[i], SDL_SRCALPHA, 64); else /* Принудительно сбрасываем флаг SDL_SRCALPHA */ SDL_SetAlpha(upsurf[i], 0, 64); /* Создаем на поверхности равномерный белый фон 56 с зеленоватым оттенком: */ DrawFillRectByCentre(upsurf[i], 28, 28, 28, 28, SDL_MapRGB(downsurf[i]->format, 255, 255, 255)); /* всю поверхность закрашиваем в непрозрачный ярко-синий цвет:*/ DrawFillRectByCentre(upsurf[i], 28, 28, 14, 14, SDL_MapRGB(upsurf[i]->format, 0, 0, 255)); /* Рисуем горизонтальную непрозрачную светло-серую полосу */ DrawFillRectByCentre(upsurf[i], 28, 28, 14, 7, SDL_MapRGB(upsurf[i]->format, 200, 200, 200)); /* Рисуем вертикальную полупрозрачную зеленую полосу с прозрачностью 50*/ DrawFillRectByCentre(upsurf[i], 28, 28, 7, 14, SDL_MapRGBA(upsurf[i]->format, 0, 255, 0, 50)); /* Рисуем подложку на месте наложения:*/ background.x = 45 - 28; background.y = 2*90 + i*90 + 40 - 28; background.w = 57; background.h = 57; SDL_FillRect(screen, &background, SDL_MapRGB(screen->format, 90, 90, 165)); /* ..и накладываем поверхность на экран:*/ dst.x = 45 - 28; dst.y = 2*90 + i*90 + 40 - 28; dst.w = 65; dst.h = 65; SDL_BlitSurface(upsurf[i], NULL, screen, &dst); } } /* и еще одну подложку чуть выше мест исходного наложения:*/ background.x = 45 - 28; background.y = 90 + 40 - 28; background.w = 57; background.h = 57; SDL_FillRect(screen, &background, SDL_MapRGB(screen->format, 90, 90, 165)); /* Подготавливаем целевые поверхности на базе "подложек" -- используем "преобразование" поверхности для создания копии */ for(i = 0; i { Uint32 key; int j; for(j = 0; j < SN; j++) { results[j][i] = SDL_ConvertSurface(downsurf[i], downsurf[i]->format,downsurf[i]->flags & (SDL_HWSURFACE|SDL_SRCCOLORKEY|SDL_SRCALPHA)); if(i & 1) /* Установлен ли бит 0 ? (самый младший)*/ { if(i & 2) /* Установлен ли бит 1 ? */ { key = SDL_MapRGBA(results[j][i]->format, 65,65,65,128); else key = SDL_MapRGB(results[j][i]->format, 65,65,65); SDL_SetColorKey(results[j][i], SDL_SRCCOLORKEY, key); } if(i & 2) /* Установлен ли бит 1 ? */ SDL_SetAlpha(results[j][i], SDL_SRCALPHA, 128); 57 else /* Принудительно сбрасываем флаг SDL_SRCALPHA */ SDL_SetAlpha(results[j][i], 0, 128); } } } } /* Накладываем на results[i][j] все upper[i] и выводим результаты: */ for(i = 0; i SDL_Rect dst, resdst, background; for(j = 0; j < SN; j++) if(results[i][j] && upsurf[i]) { dst.x = 12; /* 40 - 28 */ dst.y = 12; dst.w = 65; dst.h = 65; SDL_BlitSurface(upsurf[i], NULL, results[i][j], &dst); resdst.x = 90 + 45 + j*90 - 40; resdst.y = 2*90 + i*90; resdst.w = 81; resdst.h = 81; background = resdst; /* Рисуем светло-фиолетовую подложку на месте наложения:*/ SDL_FillRect(screen, &background, SDL_MapRGB(downsurf[i]->format, 255, 0, 255)); SDL_BlitSurface(results[i][j], NULL, screen, &resdst); } } SDL_Flip(screen); /* Принудительное обновление экрана */ /* цикл ожидания событий */ while(SDL_WaitEvent(&event)) { if(event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)) { SDL_Quit(); return 0; /* пусть 0 - нормальное завершение*/ } if(event.type == SDL_VIDEOEXPOSE) SDL_Flip(screen); } fprintf(stderr,"WaitEvent failed: %s\n",SDL_GetError()); SDL_Quit(); return 2; /* Выход с другим кодом ошибки */ } П Р И Л О Ж Е Н И Е 2 Примеры работы со шрифтами #include #include #include #include #include 58 { SDL_Surface *screen; SDL_Event event; /* Для вывода текстов */ TTF_Font *fnt1 = NULL, *fnt2 = NULL, *fnt3 = NULL, *fnt4 = NULL, *fnt5= NULL; SDL_Color text_color; SDL_Rect src; SDL_Rect dest; SDL_Surface *text_surface1 = NULL; SDL_Surface *text_surface2 = NULL; SDL_Surface *text_surface3 = NULL; SDL_Surface *text_surface4 = NULL; SDL_Surface *text_surface5 = NULL; /* Строка "Привет, Мир!" в кодировке utf8, сам текст программы в кодировке cp1251 для Dev-Cpp */ char hello_world[]="РџСЂРѐвет, РњРѐСЂ!"; unsigned long vecnt = 0; /* счетчик событий SDL_VIDEOEXPOSE */ setbuf(stderr, NULL); /* Отмена буферизации stderr для гарантированного сохранения сообщений об ошибках*/ if (SDL_Init(SDL_INIT_VIDEO)) /* инициализация SDL */ { /* При ошибке формируем сообщение и выходим */ fprintf(stderr,"Ошибка в SDL_Init: %s\n",SDL_GetError()); return 1; } if (TTF_Init()) /* инициализация SDL_ttf */ { /* При ошибке формируем сообщение и выходим */ fprintf(stderr,"Ошибка в TTF_Init: %s\n",SDL_GetError()); return 1; } atexit(SDL_Quit); /* После инициализации собственно SDL и установки atexit(SDL_Quit): */ screen=SDL_SetVideoMode(640,480,32,SDL_ANYFORMAT); if (!screen) { fprintf(stderr,"SDL mode failed: %s\n",SDL_GetError()); return 1; } /* Первый параметр следующей функции должен быть набран в среде разработки на одной строке (весь текст внутри кавычек и сами кавычки)! */ SDL_WM_SetCaption("РџСЂРѐмер в„–3. Вывод текста разнымРѐ шрРѐфтамРѐ СЃ РѐспользованРѐем SDL_ttf", NULL); /* Загружаем шрифты с нестандартным размером 29 пунктов, или ближайшим большим, имеющимся в файле шрифта. Файлы шрифтов с указанными именами должны быть в каталоге с исполняемым файлом программы! */ fnt1 = TTF_OpenFont("1.ttf", 29); fnt2 = TTF_OpenFont("Anonymous_Pro_I.ttf", 29); fnt3 = TTF_OpenFont("CharisSILR.ttf", 29); fnt4 = TTF_OpenFont("ClearSans-Thin.ttf", 29); fnt5 = TTF_OpenFont("UbuntuMono-RI.ttf", 80); /* Если хоть один шрифт не загрузился -- выходим*/ if(!(fnt1 && fnt2 && fnt3 && fnt4 && fnt5)) return 3; /* Ввод параметров*/ text_color.r = 0; text_color.g = 255; text_color.b = 0; dest.x = 200; dest.y = 100; /* Ширину и высоту выставляем с запасом: */ dest.w = 10; dest.h = 10; 59 src.x = 0; src.y = 0; /* Ширину и высоту выставляем с запасом: */ src.w = 100; src.h = 100; /* Текст для корректного отображения должен быть в UTF8! */ text_surface1 = TTF_RenderUTF8_Solid(fnt1, "РџСЂРѐвет, РњРѐСЂ!", text_color); if(text_surface1) { SDL_BlitSurface(text_surface1, &src, screen, &dest); SDL_FreeSurface(text_surface1); text_surface1 = NULL; } /* На основе результатов вывода предыдущего текста смещаем на "строчку" вниз: */ dest.y += dest.h; /* Поскольку высота и ширина нового текста может оказаться больше, "восстанавливаем запасы" */ dest.h = dest.w = 1000; text_color.r = 255; text_color.g = 0; text_color.b = 0; text_surface2 = TTF_RenderUTF8_Solid(fnt2, "РџСЂРѐвет, РњРѐСЂ!", text_color); if(text_surface2)/* сохраняем для последующего использования.*/ SDL_BlitSurface(text_surface2, NULL, screen, &dest); /* На основе результатов вывода предыдущего текста смещаем на "строчку" вниз: */ dest.y += dest.h; /* "восстанавливаем запасы" */ dest.h = dest.w = 1000; text_color.r = 0; text_color.g = 0; text_color.b = 255; text_surface3 = TTF_RenderUTF8_Solid(fnt3, hello_world, text_color); if(text_surface3) { SDL_BlitSurface(text_surface3, NULL, screen, &dest); SDL_FreeSurface(text_surface3); text_surface3 = NULL; } /* На основе результатов вывода предыдущего текста смещаем на "строчку" вниз: */ dest.y += dest.h; /* "восстанавливаем запасы" */ dest.h = dest.w = 1000; text_color.r = 255; text_color.g = 255; text_color.b = 255; text_surface4 = TTF_RenderUTF8_Solid(fnt4, hello_world, text_color); if(text_surface4) /* сохраняем для последующего использования.*/ SDL_BlitSurface(text_surface4, NULL, screen, &dest); /* 5-й шрифт. С каждой перерисовкой изменяется размер, поэтому шрифт переоткрывается. А также цвет -- приходится каждый раз делать новую поверхность. И положение на экране...*/ dest.x = 0; dest.y = 480/2; text_color.r = 255; text_color.g = 255; text_color.b = 255; dest.h = dest.w = 1000; text_surface5 = TTF_RenderUTF8_Solid(fnt5, hello_world, text_color); if(text_surface5) { SDL_BlitSurface(text_surface5, NULL, screen, &dest); SDL_FreeSurface(text_surface5); text_surface5 = NULL; } TTF_CloseFont(fnt5); /* Закрываем шрифт */ fnt5 = NULL; /* Обновление отображения измененной поверхности 60 на физическом устройстве вывода. До этого вызова все операции на поверхности производятся в памяти. */ SDL_Flip(screen); /* цикл ожидания событий */ while(SDL_WaitEvent(&event)) { if(event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)) { TTF_CloseFont(fnt1); /* Закрываем шрифт */ TTF_CloseFont(fnt2); /* Закрываем шрифт */ TTF_CloseFont(fnt3); /* Закрываем шрифт */ TTF_CloseFont(fnt4); /* Закрываем шрифт */ if(fnt5) TTF_CloseFont(fnt5); /* Закрываем шрифт */ TTF_Quit(); SDL_Quit(); return 0; /* пусть 0 - нормальное завершение*/ } if(event.type == SDL_VIDEOEXPOSE) { ++vecnt; /* Инкремент счетчика событий SDL_VIDEOEXPOSE */ text_color.r = 0; text_color.g = 255; text_color.b = 0; dest.x = 200; dest.y = 100; /* Текст для корректного отображения должен быть в UTF8! */ text_surface1 = TTF_RenderUTF8_Solid(fnt1, "РџСЂРѐвет, РњРѐСЂ!", text_color); if(text_surface1) { SDL_BlitSurface(text_surface1, NULL, screen, &dest); SDL_FreeSurface(text_surface1); text_surface1 = NULL; } dest.y += dest.h; /* Отображаем ранее сохраненную поверхность с текстом. */ if(text_surface2) SDL_BlitSurface(text_surface2, NULL, screen, &dest); /* На основе результатов вывода предыдущего текста смещаем на "строчку" вниз: */ dest.y += dest.h; /* "восстанавливаем запасы" */ dest.h = dest.w = 1000; text_color.r = 0; text_color.g = 0; text_color.b = 255; text_surface3 = TTF_RenderUTF8_Solid(fnt3, hello_world, text_color); if(text_surface3) { SDL_BlitSurface(text_surface3, NULL, screen, &dest)); SDL_FreeSurface(text_surface3); text_surface3 = NULL; } /* На основе результатов вывода предыдущего текста смещаем на "строчку" вниз: */ dest.y += dest.h; /* "восстанавливаем запасы" */ dest.h = dest.w = 1000; /* Отображаем ранее сохраненную поверхность с текстом. */ if(text_surface4) SDL_BlitSurface(text_surface4, NULL, screen, &dest)); /* 5-й шрифт переоткрывается. */ fnt5 = TTF_OpenFont("UbuntuMono-RI.ttf", vecnt*4 % 80); 61 if(fnt5) { text_color.r = vecnt % 3 == 0 ? vecnt*10 % 256 : 0; text_color.g = vecnt % 3 == 1 ? vecnt*10 % 256 : 0; text_color.b = vecnt % 3 == 2 ? vecnt*10 % 256 : 0; text_surface5 = TTF_RenderUTF8_Solid(fnt5, hello_world, text_color); if(text_surface5) { dest.x = vecnt*10 % 640; dest.y = 480/2 + vecnt*10 % (480/2); dest.h = dest.w = 1000; SDL_BlitSurface(text_surface5, NULL, screen, &dest); SDL_FreeSurface(text_surface5); text_surface5 = NULL; } TTF_CloseFont(fnt5); /* Закрываем шрифт */ } } } fprintf(stderr,"WaitEvent failed: %s\n",SDL_GetError()); SDL_Quit(); return 2; /* Выход с другим кодом ошибки */ } П Р И Л О Ж Е Н И Е 3 Примеры построения графика функции с использованием библиотеки SDL Рассмотрим два фрагмента программы с использованием библиотеки SDL_draw, отображающей в окне 640 на 480 пикселей график функции y=ln(|x|), причем x min = –32, x max = 32, (MX = MY = = 10 пикселей), а экранное положение начала координат – в центре экрана. В первом фрагменте построение производится по точкам с шагом ∆x = 0,001, во втором – отрезками с ∆x = 0,1. Инициализация, отображение осей координат, асимптот и т.п. не приводятся. /* Отображение графика функции по точкам */ /* screen – инициализированная поверхность для рисования 640 на 480 пикселей, */ const Sint16 width=640, heght=480; double xmin=-32.0, xmax=32.0, ymin, ymax; double mx=10.0, my=10.0, dx=0.001, x, y; Sint16 x0scr, y0scr, xscr, yscr; x0scr=floor(-1*xmin*mx); /* ymin – неизвестно, так нельзя: y0scr=floor(height+ymin*my); Используем соглашение о середине экрана: */ y0scr=height/2; /*целочисленное деление */ for(x=xmin;x<=xmax;x+=dx){ if((fabs(x)-1e-4)>0){ /*исключение нуля с учетом погрешности */ y=log(fabs(x)); xscr=x0scr+floor(x*mx); yscr=y0scr-floor(y*my); /*Точка синим цветом: */ Draw_Pixel(screen, xscr, yscr, 0x0000FF); } } /* Отображение графика функции отрезками */ /* screen – инициализированная поверхность для рисования 640 на 480 пикселей, */ 62 const Sint16 width=640, heght=480; double xmin=-32.0, xmax=32.0, ymin, ymax; double mx=10.0, my=10.0, dx=0.1, x1, y1, x2, y2; Sint16 x0scr, y0scr, xscr1, yscr1, xscr2, yscr2; x0scr=floor(-1*xmin*mx); /* ymin – неизвестно, так нельзя: y0scr=floor(height+ymin*my); Используем соглашение о середине экрана: */ y0scr=height/2; /*целочисленное деление */ for(x1=xmin, x2=xmin+dx;x1 /*исключение нуля с учетом погрешности */ y1=log(fabs(x1)); /*можно исключить повтор вычислений*/ y2=log(fabs(x2)); xscr1=x0scr+floor(x1*mx); yscr1=y0scr-floor(y1*my); xscr2=x0scr+floor(x2*mx); yscr2=y0scr-floor(y2*my); /*Отрезок синим цветом: */ Draw_Line(screen,xscr1,yscr1, xscr2,yscr2,0x0000FF); } } Полный текст примера попеременного рисования графика данной функции обоими способами (чередование способа при каждом наступлении события SDL_VIDEOEXPOSE) выглядит следующим образом (приведен текст файла main.c, проект в среде Dev-Cpp 4.9.9.2 создается согласно приложению 1 как консольное приложение Win32 с динамическим подключением библиотек): #include #include #include #include "SDL.h" #include "SDL_draw.h" #include "SDL_ttf.h" void draw_by_pixels(SDL_Surface *who_draw); void draw_by_line(SDL_Surface *who_draw); int main(int argc, char *argv[]) { SDL_Surface *screen; SDL_Event event; int flag = 0; if (SDL_Init(SDL_INIT_VIDEO)) /* инициализация SDL */ { /* При ошибке формируем сообщение и выходим */ fprintf(stderr,"Ошибка в SDL_Init: %s\n",SDL_GetError()); return 1; } atexit(SDL_Quit); /* После инициализации собственно SDL и установки atexit(SDL_Quit): */ screen=SDL_SetVideoMode(640,480,32,SDL_ANYFORMAT); if (!screen) { fprintf(stderr,"SDL mode failed: %s\n",SDL_GetError()); return 1; } /* Сначала рисуем по точкам синим цветом*/ draw_by_pixels(screen); /* цикл ожидания событий */ while(SDL_WaitEvent(&event)) 63 { if(event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)) { SDL_Quit(); return 0; /* пусть 0 - нормальное завершение*/ } if(event.type == SDL_VIDEOEXPOSE) { /*чередуем способы перерисовки */ if(flag) draw_by_line(screen); else draw_by_pixels(screen); flag = !flag; } } fprintf(stderr,"WaitEvent failed: %s\n",SDL_GetError()); SDL_Quit(); return 2; /* Выход с другим кодом ошибки */ } void draw_by_pixels(SDL_Surface *who_draw) { /* Отображение графика функции по точкам */ const Sint16 width=640, height=480; double xmin=-32.0, xmax=32.0, ymin, ymax; double mx=10.0, my=10.0, dx=0.001, x, y; Sint16 x0scr, y0scr, xscr, yscr; x0scr=floor(-1*xmin*mx); /* ymin - неизвестно, следовательно, так нельзя: y0scr=floor(height+ymin*my); Используем соглашение о середине экрана: */ y0scr=height/2; /*целочисленное деление */ for(x=xmin;x<=xmax;x+=dx){ if((fabs(x)-1e-4)>0){/*исключение нуля с учетом погрешности */ y=log(fabs(x)); xscr=x0scr+floor(x*mx); yscr=y0scr-floor(y*my); /*Точка синим цветом: */ Draw_Pixel(who_draw, xscr, yscr, 0x0000FF); } } } void draw_by_line(SDL_Surface *who_draw) {/* Отображение графика функции отрезками */ const Sint16 width=640, height=480; double xmin=-32.0, xmax=32.0, ymin, ymax; double mx=10.0, my=10.0, dx=0.1, x1, y1, x2, y2; Sint16 x0scr, y0scr, xscr1, yscr1, xscr2, yscr2; x0scr=floor(-1*xmin*mx); /* ymin - неизвестно, так нельзя: y0scr=floor(height+ymin*my); Используем соглашение о середине экрана: */ y0scr=height/2; /*целочисленное деление */ for(x1=xmin, x2=xmin+dx;x1 /*исключение нуля с учетом погрешности */ y1=log(fabs(x1)); /*можно исключить повтор вычислений*/ y2=log(fabs(x2)); xscr1=x0scr+floor(x1*mx); yscr1=y0scr-floor(y1*my); xscr2=x0scr+floor(x2*mx); 64 yscr2=y0scr-floor(y2*my); /*Отрезок красным цветом: */ Draw_Line(who_draw,xscr1,yscr1, xscr2,yscr2,0xFF0000); } } } В качестве второго примера рассмотрим рисование графика функции y=a+b/(x*c+d) на отрезке [xmin; xmax] с использованием максимальной площади экрана. При этом все параметры вводятся пользователем с клавиатуры. Отображение осей координат, асимптот и т.п. не приводится. #include #include #include #include #include "SDL.h" #include "SDL_draw.h" #include "SDL_ttf.h" void draw_by_pixels(SDL_Surface *who_draw); void draw_by_line(SDL_Surface *who_draw); /*Вывод рационального числа с экранным редактированием. Параметры: где рисовать (поверхность), каким шрифтом, каким цветом, в какой прямоугольной области можно отображать вводимые данные, исходное значение (значение по умолчанию) */ double input_double(SDL_Surface *who_draw, TTF_Font *fnt, SDL_Color color, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, double defval); /* Параметры функции и значения по умолчанию*/ double a=0, b=1, c=1, d=0; const Sint16 width=640, height=480; double xmin=-32.0, xmax=32.0, ymin, ymax; double mx=10.0, my=10.0; Sint16 x0scr, y0scr; int main(int argc, char *argv[]) { SDL_Surface *screen; SDL_Event event; TTF_Font *fnt; /* Для вывода текстов */ SDL_Color text_color; SDL_Rect dest; SDL_Surface *text_surface = NULL; char txtbuf[100]; int flag = 0; /* очередность использования методов рисования*/ setbuf(stderr, NULL); /* Отмена буферизации stderr для гарантированного сохранения сообщений об ошибках*/ if (SDL_Init(SDL_INIT_VIDEO)) /* инициализация SDL */ { /* При ошибке формируем сообщение и выходим */ fprintf(stderr,"Ошибка в SDL_Init: %s\n",SDL_GetError()); return 1; } if (TTF_Init()) /* инициализация SDL_ttf */ { /* При ошибке формируем сообщение и выходим */ fprintf(stderr,"Ошибка в TTF_Init: %s\n",SDL_GetError()); 65 return 1; } atexit(SDL_Quit); /* После инициализации собственно SDL и установки atexit(SDL_Quit): */ screen=SDL_SetVideoMode(640,480,32,SDL_ANYFORMAT); if (!screen) { fprintf(stderr,"SDL mode failed: %s\n",SDL_GetError()); return 1; } /* Первый параметр должен быть полностью на одной строке вместе с кавычками! */ SDL_WM_SetCaption("ПостроенРѐРµ графРѐРєР° функцРѐРѐ СЃ РѐспользованРѐем SDL. РџСЂРѐмер в„–2",NULL); /* Загружаем шрифт размером sz пунктов*/ fnt = TTF_OpenFont("ClearSans-Thin.ttf", 30); printf("fnt = %p\n", fnt); if(!fnt) return 3; /* Цвета для ввода параметров (ярко-зеленый): */ text_color.r = 0; text_color.g = 255; text_color.b = 0; /* Ввод параметров: */ dest.x = 0; dest.y = 0; text_surface = TTF_RenderUTF8_Solid(fnt, "a=", text_color); if(text_surface){ SDL_BlitSurface(text_surface, NULL, screen, &dest); SDL_FreeSurface(text_surface); text_surface = NULL; } SDL_Flip(screen); a = input_double(screen, fnt, text_color, dest.x+dest.w, dest.y, dest.x+dest.w + 200, dest.y+dest.h, a); dest.x = 0; dest.y = dest.y + dest.h; text_surface = TTF_RenderUTF8_Solid(fnt, "b=", text_color); if(text_surface){ SDL_BlitSurface(text_surface, NULL, screen, &dest); SDL_FreeSurface(text_surface); text_surface = NULL; } SDL_Flip(screen); b = input_double(screen, fnt, text_color, dest.x+dest.w, dest.y, dest.x+dest.w + 200, dest.y+dest.h, b); dest.x = 0; dest.y = dest.y + dest.h; text_surface = TTF_RenderUTF8_Solid(fnt, "c=", text_color); if(text_surface){ SDL_BlitSurface(text_surface, NULL, screen, &dest); SDL_FreeSurface(text_surface); text_surface = NULL; } SDL_Flip(screen); c = input_double(screen, fnt, text_color, dest.x+dest.w, dest.y, dest.x+dest.w + 200, dest.y+dest.h, c); dest.x = 0; dest.y = dest.y + dest.h; text_surface = TTF_RenderUTF8_Solid(fnt, "d=", text_color); if(text_surface){ SDL_BlitSurface(text_surface, NULL, screen, &dest); SDL_FreeSurface(text_surface); text_surface = NULL; } printf("before input_double(), d=%lf\n",d); SDL_Flip(screen); d = input_double(screen, fnt, text_color, dest.x+dest.w, dest.y, dest.x+dest.w + 200, dest.y+dest.h, d); dest.x = 0; dest.y = dest.y + dest.h; text_surface = TTF_RenderUTF8_Solid(fnt, "xmin=", text_color); if(text_surface){ 66 SDL_BlitSurface(text_surface, NULL, screen, &dest); SDL_FreeSurface(text_surface); text_surface = NULL; } SDL_Flip(screen); xmin = input_double(screen, fnt, text_color, dest.x+dest.w, dest.y, dest.x+dest.w + 200, dest.y+dest.h, xmin); dest.x = 0; dest.y = dest.y + dest.h; text_surface = TTF_RenderUTF8_Solid(fnt, "xmax=", text_color); if(text_surface){ SDL_BlitSurface(text_surface, NULL, screen, &dest); SDL_FreeSurface(text_surface); text_surface = NULL; } SDL_Flip(screen); xmax = input_double(screen, fnt, text_color, dest.x+dest.w, dest.y, dest.x+dest.w + 200, dest.y+dest.h, xmax); /* Расчет масштабных коэффициентов:*/ mx = (1.0 * width) / fabs(xmax-xmin); dest.x = 0; dest.y = dest.y + dest.h; memset(txtbuf,0,100); sprintf(txtbuf,"mx = %lf",mx); text_surface = TTF_RenderUTF8_Solid(fnt, txtbuf, text_color); if(text_surface){ SDL_BlitSurface(text_surface, NULL, screen, &dest); SDL_FreeSurface(text_surface); text_surface = NULL; } dest.x = 0; dest.y = dest.y + dest.h; memset(txtbuf,0,100); sprintf(txtbuf,"my = %lf",my); text_surface = TTF_RenderUTF8_Solid(fnt, txtbuf, text_color); if(text_surface){ SDL_BlitSurface(text_surface, NULL, screen, &dest); SDL_FreeSurface(text_surface); text_surface = NULL; } /* Сначала рисуем по точкам синим цветом*/ draw_by_pixels(screen); SDL_Flip(screen); /* цикл ожидания событий */ while(SDL_WaitEvent(&event)) { if(event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)) { TTF_CloseFont(fnt); /* Закрываем шрифт */ SDL_Quit(); return 0; /* пусть 0 - нормальное завершение*/ } if(event.type == SDL_VIDEOEXPOSE) { /*чередуем способы перерисовки */ if(flag) draw_by_line(screen); else draw_by_pixels(screen); flag = !flag; } } fprintf(stderr,"WaitEvent failed: %s\n",SDL_GetError()); SDL_Quit(); return 2; /* Выход с другим кодом ошибки */ } void draw_by_pixels(SDL_Surface *who_draw) {/* Отображение графика функции по точкам */ double dx=0.001, x, y; Sint16 xscr, yscr; 67 x0scr=floor(-1*xmin*mx); /* ymin - неизвестно, так нельзя: y0scr=floor(height+ymin*my); Используем соглашение о середине экрана: */ y0scr=height/2; /*целочисленное деление */ for(x=xmin; x<=xmax; x+=dx){ if((fabs(x)-1e-4)>0){ /*исключение нуля */ y=a+b/(c*x+d); xscr=x0scr+floor(x*mx); yscr=y0scr-floor(y*my); /* рисуем синим цветом только точки, помещающиеся на поверхности, иначе будет ошибка*/ if( 0<=xscr && xscr } } } void draw_by_line(SDL_Surface *who_draw) {/* Отображение графика функции отрезками */ double dx=0.1, x1, y1, x2, y2; Sint16 xscr1, yscr1, xscr2, yscr2; x0scr=floor(-1*xmin*mx); /* ymin - неизвестно, так нельзя: y0scr=floor(height+ymin*my); Используем соглашение о середине экрана: */ y0scr=height/2; /*целочисленное деление */ for(x1=xmin, x2=xmin+dx;x1 /*исключение нуля */ y1=a+b/(c*x1+d); /*можно исключить повтор вычислений*/ y2=a+b/(c*x2+d); xscr1=x0scr+floor(x1*mx); yscr1=y0scr-floor(y1*my); xscr2=x0scr+floor(x2*mx); yscr2=y0scr-floor(y2*my); /*Отрезок красным цветом (для отрезков больше проверок:*/ if( 0<=xscr1 && xscr1 } } } /* Функция вывода на поверхность одиночного символа заданным шрифтом в указанных координатах заданным цветом */ void OutSymbolFntColorXY(SDL_Surface *screen, TTF_Font *fnt, SDL_Color clr, Sint16 x, Sint16 y, int symbolcode) { /* Такая реализация корректно работает только с символами, код которых в utf8 задается 1 байтом. То есть, только символами ASCII, имеющими код от 0 до 127. Этого достаточно для записи вещественных чисел. */ SDL_Rect dest; dest.x = x; dest.y = y; сhar s[2]; s[0]=symbolcode; s[1]='\0'; SDL_Surface *TextSurface = TTF_RenderUTF8_Solid(fnt, s, clr); SDL_BlitSurface(TextSurface, NULL, screen, &dest); SDL_FreeSurface(TextSurface); // Освобождаем поверхность /* Обновляем только измененный участок целевой поверхности:*/ SDL_UpdateRect(screen,dest.x,dest.y,dest.w,dest.h); } /* Функция ввода вещественного числа. Параметры см. выше при объявлении.*/ double input_double(SDL_Surface *who_draw, TTF_Font *fnt, SDL_Color color, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, double defval) { 68 #define WHOLE 7 //кол-во знаков под целую часть мантиссы #define FRACTIONAL 6 //кол-во знаков под дробную часть мантиссы #define EXP 3 //кол-во знаков под степень #define E 308 //максимальное значение степени /* Символьный буфер для ввода и редактирования: размер исходя из заданного числа знаков, а также места по одному байту для возможного знака мантиссы и показателя, десятичной точки в мантиссе, разделителя мантиссы и показателя и завершающего NULL-терминатора.*/ char s[WHOLE+FRACTIONAL+EXP+5]; /* Все символы в нем делаем нулевыми */ memset(s,0,WHOLE+FRACTIONAL+EXP+5); /* количество и положение различных символов в буфере */ int _kol=-1, _whole=0, _fractional=0, _exp=0, _pointf=0,_minusf=0,_ef=0,_minusEf=0; /* Координаты рабочей области */ Sint16 wrk_x1=x1, x=wrk_x1, wrk_y1=y1, y=wrk_y1; SDL_Event event; int i; while ( SDL_WaitEvent(&event) ){ if (event.type == SDL_QUIT){ /* По идее, надо вернуть его обратно в очередь и пусть обрабатывает основная программа... В данном примере не реализовано. */ break; } if (event.type == SDL_KEYDOWN){ /*Если нажата клавиша...*/ if((!_pointf && _whole {// Цифровую клавиатуру пока игнорируем char digitsym = (char) event.key.keysym.sym; OutSymbolFntColorXY(who_draw, fnt, color, x,y, digitsym); x+=20; s[++_kol]=digitsym; if(!_pointf && _whole _exp=_exp+1; } } if ((event.key.keysym.sym==SDLK_BACKSPACE)&&(x!=x1)) { if(_whole<=WHOLE && !_pointf && !_ef && _whole>0 && !_fractional) _whole=_whole-1; //удаление цифры из целой части else if(_pointf && _fractional>0 && _fractional<=FRACTIONAL && !_ef && _whole) _fractional=_fractional-1;/*удаление цифры из дробной части мантиссы */ else if(!_whole && _minusf) _minusf=0; // удаление минуса перед целой частью else if (_pointf && !_fractional && !_ef && _whole) _pointf=0; //удаление точки else 69 if (_ef && !_exp && !_minusEf) _ef=0; //удаление символа exp else if (_ef && !_exp && _minusEf) _minusEf=0; //удаление минуса после exp else if (_ef && _exp<=EXP) _exp=_exp-1; //удаление цифры в степени // Смещаемся на 20 пикселей влево (одно "знакоместо") x-=20; // Затираем знакоместо черным цветом Draw_FillRect(who_draw,x,y,20,42,0); // Обновляем экран SDL_UpdateRect(who_draw,0,0,width,height); _kol=_kol-1; /* Уменьшаем число символов */ continue; /*Продолжаем ожидание событий */ } if(event.key.keysym.sym==SDLK_MINUS && ((!_minusf && !_whole && !_ef) || (!_minusEf && _ef && !_exp))) { OutSymbolFntColorXY(who_draw, fnt, color, x,y,SDLK_MINUS); x+=20; s[++_kol]=45; if (!_minusf && !_whole && !_ef) _minusf=1; else _minusEf=1; continue; } if (event.key.keysym.sym==SDLK_PERIOD && !*pointf && !_ef){ if (!_whole){ s[++_kol]=48; _whole=1; OutSymbolFntColorXY(who_draw,fnt,color,x,y,SDLK_0); } s[++_kol]=46; OutSymbolFntColorXY(who_draw, fnt, color,x,y,SDLK_PERIOD); x+=20; _pointf=1; continue; } if (event.key.keysym.sym==SDLK_e && !_ef){ OutSymbolFntColorXY(who_draw, fnt, color,x,y,SDLK_e); x+=20; s[++_kol]=101; _ef=1; continue; } if (event.key.keysym.sym==SDLK_RETURN && _kol!=-1) { /* Завершение ввода */ double tmp; s[_kol+1]='\0'; sscanf(s,"%lf",&tmp); /*Отсутствует проверка ввода! */ return tmp; } if (event.key.keysym.sym == SDLK_ESCAPE) /* Будет возвращено значение по умолчанию. */ break; } /* Конец обработки события SDL_KEYDOWN */ } /* Конец цикла обработки событий */ return defval; } /* конец тела функции input_double */ Библиографический список 70 1. Керниган, Брайен, Ритчи, Деннис. Язык программирования C. 2-е изд.: пер. с англ. М.: Изд. дом «Вильямс», 2013. 304 с. 2. SDL Library Documentation. URL: www.libsdl.org/release/SDL-1.2.15/docs/ html/index.html (дата обращения: 28.11.2013). О Г Л А В Л Е Н И Е Введение. Работа с клавиатурой и дисплеем ............................................................. 3 1. Основные возможности библиотеки семейства SDL ............................................. 8 2. Начало работы с SDL 1.2.15, SDL_draw 1.2.13 и SDL_ttf 2.0.11 в интегри-рованной среде разработки Dev-Cpp 4.9.9.2 под управлением Windows XP ................................................................... 9 3. Подключение и инициализация библиотеки SDL ................................................ 13 4. Графические примитивы библиотеки SDL_draw ................................................. 17 5. Рисование сложных фигур ..................................................................................... 19 6. Работа с поверхностями в библиотеке SDL .......................................................... 30 7. Имитация движения при выводе на дисплей ........................................................ 38 8. Вывод текста с помощью библиотеки SDL_ttf ..................................................... 43 9. Обработка событий средствами библиотеки SDL ................................................ 46 10. Построение графиков функций на дискретных устройствах отображения информации 51 П р и л о ж е н и е 1. Примеры наложения поверхностей ....................................... 53 П р и л о ж е н и е 2. Примеры работы со шрифтами .............................................. 57 П р и л о ж е н и е 3. Примеры построения графика функции с использова-нием библиотеки SDL 61 Библиографический список......................................................................................... 69 Гущин Артем Николаевич Применение библиотеки SDL для разработка программ на языке C Редактор Г.М. Звягина Корректор Л.А. Петрова Подписано в печать 9.10.2014. Формат бумаги 60х84/16. Бумага документная. Печать трафаретная. Усл. печ. л. 6,85. Тираж 100 экз. Заказ № 150. Балтийский государственный технический университет Типография БГТУ 190005, С.-Петербург, 1-я Красноармейская ул., д.1 |