ZL31ARM: implementacja funkcji graficznych 2D
Funkcja czyszcząca ekran przyjmuje jako parametr wartość koloru z palety BRG, strukturę wartości którego opisane wyżej, i wypełnia nim cały ekran. Ostatnia funkcja z danej biblioteki ustawia kontrast. W celu jej regulacji można wykorzystać następujący fragment kodu w pętli while i który sprawdza czy włączony jest przycisk JOY_UP lub JOY_DOWN i odpowiednio dostraja wartość:
Delay(0xFFFF); if(GPIO_ReadInputDataBit(JOY_PORT, JOY_UP) == 0) SetContrast(contrast == 63 ? contrast : ++contrast); else if(GPIO_ReadInputDataBit(JOY_PORT, JOY_DOWN) == 0) SetContrast(contrast == -64 ? contrast : --contrast);
Warto zauważyć, że zmienna contrast przekazywana jako parametr przyjmuje wartości z zakresu od (-64) do 63. Wynika to z budowy sterownika PCF8833 odpowiedzialnego za pracę wyświetlacza. Poniższy kod rysuje kilka punktów testowych na ekranie:
LCDSetPixel( 1, 1,0x00F);//GREEN LCDSetPixel(130, 1,0x0F0);//RED LCDSetPixel(130,130,0xF00);//BLUE LCDSetPixel( 1,130,0x000);//BLACK LCDSetPixel( 65, 65,0xFFF);//WHITE
W zależności od tego czym został wypełniony ekran funkcją LCDClearScreen(), niektóre kolory mogą być słabo widoczne/rozróżnialne na danym tle.
Rysowanie linii
W prezentowanym projekcie za początek układu współrzędnych OXY został przyjęty punkt centralny ekranu i w tym celu na początku pliku graphics.c umieszczono następującą definicję, którą będzie wykorzystywana w funkcjach rysujących opisanych w danym pliku:
#define DISPLAY_CENTER 132/2
W funkcjach rysujących zawartych w pliku graphics.c w przypadku podawania współrzędnych wartość powinna zawierać się w przedziale od -65 do 64 włącznie co pozwoli na prawidłowe wyświetlenie wszystkich punktów.
Pierwszą i elementarną funkcją w pliku graphics.c jest funkcja rysująca linię drawLine(). Wywołuje się ją z podaniem dwóch punktów końcowych i koloru linii, a jej struktura wygląda w następujący sposób:
void drawLine(int x1, int y1, int x2, int y2, unsigned int color) { //Wyznaczanie roznicy miedzy wspolrzednymi punktami int dx = x2 - x1; int dy = y2 - y1; //Rysuj punkt poczatkowy LCDSetPixel(x1+DISPLAY_CENTER, y1+DISPLAY_CENTER, color); //Zmienna niezalezna jest x if (abs(dx) >= abs(dy) || abs(dx) != 0){ float a = (float) dy / (float) dx; //Wyznaczenie wspolczynnika kierunkowego float b = y1 - a*x1; //Wyznaczenie przesuniecia dx = (dx < 0) ? -1 : 1; //W zaleznosci od tego ktory punkt znajduje //sie "wyzej" rysowanie bedzie odbywac sie w //kierunku dodatnich lub ujemnych wartosci //Rysuj kolejne punkty dopoki nie osiagnieto punktu x2 while (x1 != x2){ x1 += dx; LCDSetPixel(x1+DISPLAY_CENTER, lround(a*x1 + b)+DISPLAY_CENTER, color); } } //Zmienna niezalezna jest y else{ float a = (float) dx / (float) dy; //Wyznaczenie wspolczynnika kierunkowego float b = x1 - a*y1; //Wyznaczenie przesuniecia dy = (dy < 0) ? -1 : 1; //Rusuj kolejne punkty dopoki nie osiagnieto punktu y2 while (y1 != y2){ y1 += dy; LCDSetPixel(lround(a*y1 + b)+DISPLAY_CENTER, y1+DISPLAY_CENTER, color); } } }
Cała procedura polega na wybraniu zmiennej niezależnej x (lub y) znalezieniu współczynników funkcji liniowej opisanej równaniem y=ax+b oraz narysowaniu punktów zgodnie z funkcją y=f(x) (lub x=f(y)) za pomocą wcześniej opisanej funkcji LCDSetPixel(). Przykład rysujący 3 przekątne linie:
drawLine(-65,-65, 64, 64, 0x00F);//GREEN drawLine(-65,-55, 54, 64, 0x0F0);//RED drawLine(-55,-65, 64, 54, 0xF00);//BLUE
Rysowanie prostokąta
Rysowanie danej figury jest realizowane na dwa sposoby, z których pierwszy (standardowy) wyświetla tylko same boki prostokąta (za pomocą funkcji LCDSetPixel()), a drugi wypełnia zadanym kolorem obszar wyznaczony przez tą figurę. Podobnie jak w przypadku linii należy podać 2 punkty (x,y) leżące na przekątnej prostokąta. Wybór między tymi sposobami jest dokonywany przez podanie parametru style (podanie 1 powoduje rysowanie „pełnego” prostokąta, w innym wypadku będzie on „pusty”). Struktura danej funkcji wygląda następująco:
void drawRectangle(int x1, int y1, int x2, int y2, unsigned int color, unsigned char style){ unsigned char i, j; //Wyznaczenie dlugosci bokow int a = abs(x2 - x1); int b = abs(y2 - y1); switch(style){ //Rysuj pelny prostokata z wypelnieniem zadanym kolorem case 1:{ for(i=0; i < a; i++){ for(j=0; j < b; j++){ LCDSetPixel(x1+DISPLAY_CENTER+i, y1+DISPLAY_CENTER+j, color); } } break; } //Rysuj 4 boki prostokata z zadanym kolorem default:{ drawLine(x1,y1,x1,y2,color); drawLine(x1,y1,x2,y1,color); drawLine(x1,y2,x2,y2,color); drawLine(x2,y1,x2,y2,color); break; } } }
Przykład rysowania „pustych” i „pełnych” prostokątów:
//Rysowanie pustych prostokątów testowych drawRectangle(-50,-40,50,40,RED); drawRectangle(-40,-30,40,30,GREEN); drawRectangle(-30,-20,30,20,BLUE); //Rysowanie pelnych prostokątów testowych drawRectangle(-50,-40,50,40,RED,1); drawRectangle(-40,-30,40,30,GREEN,1); drawRectangle(-30,-20,30,20,BLUE,1);