Graph13 Kütüphanesi
Retro bilgisayarAşağıdaki kaynak kod "Tr-Demoscene: http://www.tr-demoscene.info/" forumunda yalnızca eğitici olması amacıyla yayınladığım bir 13h (320x200x256) grafik modu kütüphanesinin geliştirilmiş versiyonudur ve Turbo C++ ile derlenebilir. Ufak değişikliklerle diğer DOS tabanlı derleyicilere de modifiye edilmesi mümkündür.
Aslında bu kütüphane tek dosyadan ibaret değildi ancak hem dergiye eklenmesini kolaylaştırmak, hem de birden fazla dosya içeren projeleri derlemede sorun yaşayan başlangıç seviyesindeki C/C++ programcılarını düşünerek tüm fonksiyonları tek bir CPP dosyasında birleştirdim. Normal koşullarda projelerinizi dosyalara bölerek geliştirmenizi ve her .c/.cpp dosyası için bir .h (header) dosyası kullanmanızı tavsiye ederim.
Tr-Demoscene forumunda yayınlanan versiyonda sınıflarda private değişken kullanımı yoktu, sınıfların tüm değişkenleri doğrudan erişilebilir bir şekilde public tanımlanmıştı. Bu aslında yanlış bir kullanımdır ve özel bir amacı olmadığı sürece genellikle tembellik belirtisidir. Bu yeni versiyonda tembellik etmeyip, sınıfları olması gerektiği yapıya çevirdim. Private değişken kullanımı özellikle hafızada oluşabilecek bazı taşmaları önlemek için ideal bir kullanımdır.
Bu kaynak kodu yayınlamaktaki amacım, bu saatten sonra DOS'da 13h modunda bir şeyler yapılmasına yardımcı olmak değil, nesneye yönelik programlama (OOP) konusunda elinizde açıklamalı bir kaynak kod bulunmasının yararlı olacağını düşünmemdir. Kodun içerisinde yeterli yorum olduğu için daha fazla açıklama yapmaya gerek duymuyorum. Özellikle overloaded fonksiyon ve overloaded methodları; yani aynı isme sahip üye fonksiyonlarını ve bu fonksiyonların parametrelerinden diğer sınıfların nasıl kullanıldığını incelemenizi tavsiye ediyorum.

Plazma'nın ilerleyen sayıları için OOP konusunda Win32 tabanlı kütüphane ve programlar da hazırlamayı düşünüyorum. Ancak öncelikle elimizdekilerden kurtulalım...
Nesneye yönelik programlama konusunda başlangıç seviyesinde olanlara başarılar ve iyi çalışmalar dilerim.
Not: Kaynak kodu renklendirme özelliği olan bir C editöründe ya da C dosyalarını renklendirebilen bir text editörde incelemenizi tavsiye ederim.
/** * Icerikler */ #include #include #include
/** * Tanımlar */ #define CHAR03 0x03 #define INT_VIDEO 0x10 #define VGA13 0x13
/** * Sınıflar */
// POINT2D Sınıfı class POINT2D { public: POINT2D(); POINT2D(POINT2D *p2dPoint); POINT2D(int xVal, int yVal); ~POINT2D(); int getX(); int getY(); void setX(int newX); void setY(int newY); private: int x; int y; };
void POINT2D::POINT2D() { // Boş } void POINT2D::POINT2D(POINT2D *p2dPoint) { x = p2dPoint->x; y = p2dPoint->y; } void POINT2D::POINT2D(int xVal, int yVal) { x = xVal; y = yVal; } void POINT2D::~POINT2D() { // Boş } int POINT2D::getX() { return x; } int POINT2D::getY() { return y; } void POINT2D::setX(int newX) { x = newX; } void POINT2D::setY(int newY) { y = newY; }
// RECT Sınıfı class RECT { public: RECT(); RECT(RECT *rctRect); RECT(POINT2D *p2dPoint1, POINT2D *p2dPoint2); RECT(int x1Val, int y1Val, int x2Val, int y2Val); ~RECT(); int getX1(); int getY1(); int getX2(); int getY2(); void setX1(int newX1); void setY1(int newY1); void setX2(int newX2); void setY2(int newY2); private: int x1; int y1; int x2; int y2; };
void RECT::RECT() { // Boş } void RECT::RECT(RECT *rctRect) { x1 = rctRect->x1; y1 = rctRect->y1; x2 = rctRect->x2; y2 = rctRect->y2; } void RECT::RECT(POINT2D *p2dPoint1, POINT2D *p2dPoint2) { x1 = p2dPoint1->getX(); y1 = p2dPoint1->getY(); x2 = p2dPoint2->getX(); y2 = p2dPoint2->getY(); } void RECT::RECT(int x1Val, int y1Val, int x2Val, int y2Val) { x1 = x1Val; y1 = y1Val; x2 = x2Val; y2 = y2Val; } void RECT::~RECT() {
// Boş } int RECT::getX1() { return x1; } int RECT::getY1() { return y1; } int RECT::getX2() { return x2; } int RECT::getY2() { return y2; } void RECT::setX1(int newX1) { x1 = newX1; } void RECT::setY1(int newY1) { y1 = newY1; } void RECT::setX2(int newX2) { x2 = newX2; } void RECT::setY2(int newY2) { y2 = newY2; }
// RGB Sınıfı class RGB { public: RGB(); RGB(RGB *rgbColor); RGB(unsigned char rVal, unsigned char gVal, unsigned char bVal); ~RGB(); int getR(); int getG(); int getB(); void setR(int newR); void setG(int newG); void setB(int newB); private: unsigned char r; unsigned char g; unsigned char b; };
void RGB::RGB() { // boş } void RGB::RGB(RGB *rgbColor) { r = rgbColor->r; g = rgbColor->g; b = rgbColor->b; } void RGB::RGB(unsigned char rVal, unsigned char gVal, unsigned char bVal) { r = rVal; g = gVal; b = bVal; } void RGB::~RGB() { // boş } int RGB::getR() { return r; } int RGB::getG() { return g; } int RGB::getB() { return b; } void RGB::setR(int newR) { r = newR; } void RGB::setG(int newG) { g = newG; } void RGB::setB(int newB) { b = newB; }
/** * Global Değişkenler */ char far *VGAMAP = (char far *) MK_FP(0xA000, 0);
/** * Prototip Fonksiyonlar */ void SetScreen(int screenMode); RGB GetColor(unsigned char color); void SetColor(unsigned char color, unsigned char r, unsigned char g, unsigned char b); void SetColor(unsigned char color, RGB *rgbColor); void CycleLeft(unsigned char continues); void CycleRight(unsigned char continues); void Plot(unsigned int x, unsigned char y, unsigned char color);
void Plot(POINT2D *p2dPoint, unsigned char color); void DrawLine(int x1, int y1, int x2, int y2, unsigned char color); void DrawLine(POINT2D *p2dPoint1, POINT2D *p2dPoint2, unsigned char color); void DrawLine(RECT *rctRect, unsigned char color); void DrawRectangle(int x1, int y1, int x2, int y2, unsigned char color); void DrawRectangle(POINT2D *p2dPoint1, POINT2D *p2dPoint2, unsigned char color); void DrawRectangle(RECT *rctRect, unsigned char color); void DrawCircle(int cx, int cy, int r, unsigned char color); void DrawCircle(POINT2D *p2dPoint, int r, unsigned char color); void FillRectangle(int x1, int y1, int x2, int y2, unsigned char color); void FillRectangle(POINT2D *p2dPoint1, POINT2D *p2dPoint2, unsigned char color); void FillRectangle(RECT *rctRect, unsigned char color); void FillCircle(int cx, int cy, int r, unsigned char color); void FillCircle(POINT2D *p2dPoint, int r, unsigned char color);
/** * Ana Fonksiyon */ void main() { // Değişken tanımları int x, y, i; POINT2D myPoint1; POINT2D myPoint2(40, 40); RECT myRect1; myPoint1.setX(30); myPoint1.setY(30);
// 320x200 256 renk ekran moduna geç SetScreen(VGA13);
// Palet oluştur // 0 - 63 kırmızı tonları (0 : en koyu @siyah@; 63 : en açık @kırmızı@) // 64 - 127 yeşil tonları (64 : en koyu @siyah@; 127 : en açık @yeşil@) // 128 - 191 mavi tonları (128 : en koyu @siyah@; 191 : en açık @mavi@) // 192 - 255 gri tonları (192 : en koyu @siyah@; 255 : en açık @beyaz@) for(i = 0; i <= 63; i++) SetColor(i, i, 0, 0); // kırmızı for(i = 64; i <= 127; i++) SetColor(i, 0, (i - 64), 0); // yeşil for(i = 128; i <= 191; i++) SetColor(i, 0, 0, (i - 128)); // mavi for(i = 192; i <= 255; i++) SetColor(i, (i - 192), (i - 192), (i - 192)); // gri
// Ekrana birkaç örnek nokta bas Plot(30, 40, 234); // Birinci kullanım biçimi Plot(&myPoint1, 60); // İkinci kullanım biçimi Plot(&myPoint2, 92); Plot(&POINT2D(40, 30), 182); // Üçüncü kullanım biçimi
// Ekrana birkaç örnek çizgi çek // Çizgilerin başlangıç ve bitişlerini plot ile işaretle
// Çizgi 1 myPoint1.setX(80); myPoint1.setY(150); myPoint2.setX(213); myPoint2.setY(48); DrawLine(&myPoint1, &myPoint2, 63); Plot(&myPoint1, 255); Plot(&myPoint2, 255);
// Çizgi 2 myPoint1.setX(80); myPoint1.setY(48); myPoint2.setX(213); myPoint2.setY(150); DrawLine(&myPoint1, &myPoint2, 63); Plot(&myPoint1, 255);
Plot(&myPoint2, 255);
// Çizgi 3 myPoint1.setX(40); myPoint1.setY(110); myPoint2.setX(77); myPoint2.setY(121); myRect1 = &RECT(&myPoint1, &myPoint2); DrawLine(&myRect1, 63); Plot(&myPoint1, 255); Plot(&myPoint2, 255);
// Çizgilerden bir daire çiz for(i = 0; i < 512; i++) { x = 250 + 55 * cos((float)i / 256 * M_PI); y = 100 + 55 * sin((float)i / 256 * M_PI); DrawLine(250, 100, x, y, x + y); }
// Ekrana birkaç örnek dikdörtgen çiz
// Dikdörtgen 1 DrawRectangle(70, 170, 10, 183, 49);
// Dikdörtgen 2 myPoint1.setX(80); myPoint1.setY(160); myPoint2.setX(95); myPoint2.setY(190); DrawRectangle(&myPoint1, &myPoint2, 117);
// Dikdörtgen 3 myRect1.setX1(170); myRect1.setY1(160); myRect1.setX2(105); myRect1.setY2(190); DrawRectangle(&myRect1, 185);
// Ekrana birkaç örnek içi dolu dikdörtgen çiz
// İçi Dolu Dikdörtgen 1 FillRectangle(68, 172, 12, 181, 49);
// İçi Dolu Dikdörtgen 2 myPoint1.setX(85); myPoint1.setY(165); myPoint2.setX(90); myPoint2.setY(185); FillRectangle(&myPoint1, &myPoint2, 127);
// İçi Dolu Dikdörtgen 3 myRect1.setX1(250); myRect1.setY1(165); myRect1.setX2(310); myRect1.setY2(185); FillRectangle(&myRect1, 63);
// Ekrana birkaç örnek çember çiz
// Çember 1 DrawCircle(100, 100, 20, 255);
// Diğer iç içe dizilmiş çemberler myPoint1 = &POINT2D(150, 40); for(i = 0; i < 30; i++) DrawCircle(&myPoint1, i, i * 12);
// Ekrana birkaç örnek daire çiz
// Daire 1 FillCircle(100, 100, 18, 44);
// Diğer iç içe dizilmiş daireler myPoint1 = &POINT2D(96, 30); for(i = 20; i >= 0; i--)
FillCircle(&myPoint1, i, i * 16);
// Bir tuşa basılana kadar bekle getch();
// Renkleri kaydır while(!kbhit()) { CycleLeft(1); delay(50); } getch(); while(!kbhit()) { CycleRight(0); delay(50); }
// 80x25 karakter ekran moduna geç SetScreen(CHAR03); }
/** * Name : SetScreen * Desc : 0x10 interruptini kullanarak ekran modunu değiştirir. * Input : (int)screenMode */ void SetScreen(int screenMode) { union REGS regs; regs.x.ax = screenMode; int86(INT_VIDEO, ®s, ®s); }
/** * Name : GetColor * Desc : Parametreden gelen sıradaki palet rengini okur. * Input : (unsigned char)color * Output: (RGB) */ RGB GetColor(unsigned char color) { RGB rgbColor; outportb(0x3c7, color); rgbColor.setR(inportb(0x3c9)); rgbColor.setG(inportb(0x3c9)); rgbColor.setB(inportb(0x3c9)); return rgbColor; }
/** * Name : SetColor * Desc : Palet renklerini değiştirir. * Input : (unsigned char)color * (unsigned char)r * (unsigned char)g * (unsigned char)b */ void SetColor(unsigned char color, unsigned char r, unsigned char g, unsigned char b) { outportb(0x3c8, color); outportb(0x3c9, r); outportb(0x3c9, g); outportb(0x3c9, b); }
/** * Name : SetColor * Desc : Overloaded SetColor fonksiyonu. (r,g,b) renklerini * RGB sınıfından tek bir değişkenden alır. * Input : (unsigned char)color * (RGB *)rgbColor */ void SetColor(unsigned char color, RGB *rgbColor) { outportb(0x3c8, color); outportb(0x3c9, rgbColor->getR()); outportb(0x3c9, rgbColor->getG()); outportb(0x3c9, rgbColor->getB()); }
/** * Name : CycleLeft * Desc : Palet renklerini sola kaydırır * Input : (unsigned char)continues */ void CycleLeft(unsigned char continues) { RGB rgbTemp; int i; if(continues == 1) rgbTemp = &GetColor(0); for(i = 0; i <= 254; i++) SetColor(i, &GetColor(i + 1)); if(continues == 1) SetColor(255, &rgbTemp); }
/** * Name : CycleRight * Desc : Palet renklerini sağa kaydırır * Input : (unsigned char)continues */ void CycleRight(unsigned char continues) { RGB rgbTemp; int i; if(continues == 1) rgbTemp = &GetColor(255); for(i = 255; i >= 1; i--) SetColor(i, &GetColor(i - 1)); if(continues == 1) SetColor(0, &rgbTemp); }
/** * Name : Plot * Desc : Parametreden gelen (x,y) koordinatlarına, yine parametreden * gelen rengi basar. * Input : (unsigned int)x * (unsigned char)y * (unsigned char)color */ void Plot(unsigned int x, unsigned char y, unsigned char color) { /******************************** * Formülün Çıkarılışı * ********************************* * (y * 320) + x => * * (y * 256) + (y * 64) + x => * * (y * 2^8) + (y * 2^6) + x => * * (y << 8) + (y << 6) + x *
********************************/ VGAMAP[(y << 8) + (y << 6) + x] = color; }
/** * Name : Plot * Desc : Overloaded Plot fonksiyonu. (x,y) koordinatlarını POINT2D * sınıfından tek bir değişkenden alır. * Input : (POINT2D *)p2dPoint * (unsigned char)color */ void Plot(POINT2D *p2dPoint, unsigned char color) { VGAMAP[(p2dPoint->getY() << 8) + (p2dPoint->getY() << 6) + p2dPoint->getX()] = color; }
/** * Name : DrawLine * Desc : Parametreden gelen (x1,y1)-(x2,y2) koordinatları arasına * çizgi çeker. 'a ihtiyaç duymaz. * Bresenham algoritması kullanır. * Input : (int)x1 * (int)y1 * (int)x2 * (int)y2 * (unsigned char)color */ void DrawLine(int x1, int y1, int x2, int y2, unsigned char color) { int dx, dy, x, y, a = 0; dx = (x1 - x2 > 0) ? x1 - x2 : x2 - x1; // Yatay düzlemdeki genişlik dy = (y1 - y2 > 0) ? y1 - y2 : y2 - y1; // Dikey düzlemdeki uzunluk if(dx > dy) // Yatay düzlemde geniş ise { x = x1; y = y1; while(1) { Plot(x, y, color); a += dy; if(a >= dx) { a -= dx; y += (y1 > y2) ? -1 : 1; } if(x == x2) break; x += (x1 > x2) ? -1 : 1; } } else // Dikey düzlemde uzun ise { x = x1; y = y1; while(1) { Plot(x, y, color); a += dx; if(a >= dy) { a -= dy; x += (x1 > x2) ? -1 : 1; } if(y == y2) break; y += (y1 > y2) ? -1 : 1;
/** * Name : DrawLine * Desc : Overloaded DrawLine fonksiyonu. (x1,y1) ve (x2,y2) yerine * POINT2D sınıfından iki değişken kullanılır. * Input : (POINT2D *)p2dPoint1 * (POINT2D *)p2dPoint2 * (unsigned char)color */ void DrawLine(POINT2D *p2dPoint1, POINT2D *p2dPoint2, unsigned char color) { DrawLine(p2dPoint1->getX(), p2dPoint1->getY(), p2dPoint2->getX(), p2dPoint2->getY(), color); }
/** * Name : DrawLine * Desc : Overloaded DrawLine fonksiyonu. (x1,y1) ve (x2,y2) yerine * RECT sınıfından bir değişken kullanılır. * Input : (RECT *)rctRect * (unsigned char)color */ void DrawLine(RECT *rctRect, unsigned char color) { DrawLine(rctRect->getX1(), rctRect->getY1(), rctRect->getX2(), rctRect->getY2(), color); }
/** * Name : DrawRectangle * Desc : Parametreden gelen (x1,y1)-(x2,y2) koordinatları arasına * dikdörtgen çeker. 'a ihtiyaç duymaz. * Input : (int)x1 * (int)y1 * (int)x2 * (int)y2 * (unsigned char)color */ void DrawRectangle(int x1, int y1, int x2, int y2, unsigned char color) { int x, y;
// Yatay çizgiler if(x1 < x2) { for(x = x1; x <= x2; x++) { Plot(x, y1, color); Plot(x, y2, color); } } else { for(x = x2; x <= x1; x++) { Plot(x, y1, color); Plot(x, y2, color); } }
// Dikey Çizgiler if(y1 < y2) { for(y = y1; y <= y2; y++) {
Plot(x1, y, color); Plot(x2, y, color); } } else { for(y = y2; y <= y1; y++) { Plot(x1, y, color); Plot(x2, y, color); } } }
/** * Name : DrawRectangle * Desc : Overloaded DrawRectangle fonksiyonu. (x1,y1) ve (x2,y2) yerine * POINT2D sınıfından iki değişken kullanılır. * Input : (POINT2D *)p2dPoint1 * (POINT2D *)p2dPoint2 * (unsigned char)color */ void DrawRectangle(POINT2D *p2dPoint1, POINT2D *p2dPoint2, unsigned char color) { DrawRectangle(p2dPoint1->getX(), p2dPoint1->getY(), p2dPoint2->getX(), p2dPoint2->getY(), color); }
/** * Name : DrawRectangle * Desc : Overloaded DrawRectangle fonksiyonu. (x1,y1) ve (x2,y2) yerine * RECT sınıfından bir değişken kullanılır. * Input : (RECT *)rctRect * (unsigned char)color */ void DrawRectangle(RECT *rctRect, unsigned char color) { DrawRectangle(rctRect->getX1(), rctRect->getY1(), rctRect->getX2(), rctRect->getY2(), color); }
/** * Name : DrawCircle * Desc : Parametreden gelen (x,y) koordinatlarından itibaren r * yarıçaplı çember çizer. Bresenham algoritması kullanır. * 'a ihtiyaç duymaz. * Input : (int)x * (int)y * (int)r * (unsigned char)color */ void DrawCircle(int cx, int cy, int r, unsigned char color) { int x, y, a;
// İlk yarıyı çiz x = r; y = 0; a = 0; while(x >= y) { Plot(cx + x, cy + y, color); Plot(cx + x, cy - y, color); Plot(cx - x, cy + y, color); Plot(cx - x, cy - y, color); y++; a += y; if(a > x)
{ x--; a -= x; } }
// İkinci yarıyı çiz x = 0; y = r; a = 0; while(y >= x) { Plot(cx + x, cy + y, color); Plot(cx + x, cy - y, color); Plot(cx - x, cy + y, color); Plot(cx - x, cy - y, color); x++; a += x; if(a > y) { y--; a -= y; } } }
/** * Name : DrawCircle * Desc : Overloaded DrawCircle fonksiyonu. (x1,y1) yerine POINT2D * sınıfından bir değişken kullanılır. * Input : (POINT2D *)p2dPoint * (int)r * (unsigned char)color */ void DrawCircle(POINT2D *p2dPoint, int r, unsigned char color) { DrawCircle(p2dPoint->getX(), p2dPoint->getY(), r, color); }
/** * Name : FillRectangle * Desc : Parametreden gelen (x1,y1)-(x2,y2) koordinatları arasına * içi dolu dikdörtgen çeker. 'a ihtiyaç duymaz. * Input : (int)x1 * (int)y1 * (int)x2 * (int)y2 * (unsigned char)color */ void FillRectangle(int x1, int y1, int x2, int y2, unsigned char color) { int x, y; if(y1 < y2) { for(y = y1; y <= y2; y++) { if(x1 < x2) { for(x = x1; x <= x2; x++) Plot(x, y, color); } else { for(x = x2; x <= x1; x++) Plot(x, y, color); }
} } else { for(y = y2; y <= y1; y++) { if(x1 < x2) { for(x = x1; x <= x2; x++) Plot(x, y, color); } else { for(x = x2; x <= x1; x++) Plot(x, y, color); } } } }
/** * Name : FillRectangle * Desc : Overloaded FillRectangle fonksiyonu. (x1,y1) ve (x2,y2) yerine * POINT2D sınıfından iki değişken kullanılır. * Input : (POINT2D *)p2dPoint1 * (POINT2D *)p2dPoint2 * (unsigned char)color */ void FillRectangle(POINT2D *p2dPoint1, POINT2D *p2dPoint2, unsigned char color) { FillRectangle(p2dPoint1->getX(), p2dPoint1->getY(), p2dPoint2->getX(), p2dPoint2->getY(), color); }
/** * Name : FillRectangle * Desc : Overloaded FillRectangle fonksiyonu. (x1,y1) ve (x2,y2) yerine * RECT sınıfından bir değişken kullanılır. * Input : (RECT *)rctRect * (unsigned char)color */ void FillRectangle(RECT *rctRect, unsigned char color) { FillRectangle(rctRect->getX1(), rctRect->getY1(), rctRect->getX2(), rctRect->getY2(), color); }
/** * Name : FillCircle * Desc : Parametreden gelen (x,y) koordinatlarından itibaren r * yarıçaplı daire çizer. Bresenham algoritması kullanır. * 'a ihtiyaç duymaz. * Input : (int)x * (int)y * (int)r * (unsigned char)color */ void FillCircle(int cx, int cy, int r, unsigned char color) { int x, y, i, a;
// İlk yarıyı çiz x = r; y = 0; a = 0; while(x >= y) { for(i = cx - x; i <= cx + x; i++)
{ Plot(i, cy + y, color); Plot(i, cy - y, color); } y++; a += y; if(a > x) { x--; a -= x; } }
// İkinci yarıyı çiz x = 0; y = r; a = 0; while(y >= x) { for(i = cx - x; i <= cx + x; i++) { Plot(i, cy + y, color); Plot(i, cy - y, color); } x++; a += x; if(a > y) { y--; a -= y; } } }
/** * Name : FillCircle * Desc : Overloaded FillCircle fonksiyonu. (x1,y1) yerine POINT2D * sınıfından bir değişken kullanılır. * Input : (POINT2D *)p2dPoint * (int)r * (unsigned char)color */ void FillCircle(POINT2D *p2dPoint, int r, unsigned char color) { FillCircle(p2dPoint->getX(), p2dPoint->getY(), r, color); }
Benimle irtibata geçmek isteyenler için e-mail adresim;
skate <at> glance <dot> ws (mailto:skate@glance.ws)
Emir Akaydın
Skate / Glance