الدروس المستفادة حول SDL 2: الدرس 4 - تمديد PNG

مرحبا بالجميع! هذا هو الدرس الرابع في SDL 2. قررت دمج الدرسين في واحد ، حيث أنهما في الأصل صغيران. ولكن يمكن العثور عليها هنا وهنا . حسنًا ، لنبدأ الدرس.

أولاً ، سنقرر ما سنفعله. اليوم سوف نتعلم كيفية تحميل الصور من ملحق آخر (وليس BMP) ، وهي: PNG. قم بإعادة الصورة بتنسيق مختلف لتسريع العمل وتغيير حجم الصورة. سوف نعمل مع هذه الصورة:

صورة

تركيب


لذلك ، أولاً نتعلم كيفية تنزيل PNG. لا تقوم مجموعة ميزات SDL 2 القياسية بتحميل صور بتنسيق غير BMP. لتنزيل تنسيق مختلف ، تحتاج إلى تثبيت الامتداد.

فيما يلي التعليمات:

نوافذ
تذهب إلى هذه الصفحة وتنزيل أرشيفات ZIP أو TAR.GZ من قسم مكتبات التنمية . قم بفكها ورميها في المجلد باستخدام برنامج التحويل البرمجي.

لينكس
إذا كان نظامك يستخدم دبيان ، فأنت بحاجة إلى إدخال هذه الأوامر:

apt-cache search libsdl2-image apt-get install libsdl2-image-dev 

إذا تم استخدام Yellowdog Updater ، تم التعديل ، فأنت تدخل هذه الأوامر:

 yum search SDL2_image-devel yum  SDL2_image-devel 


نظام التشغيل Mac OS
قم بتنزيل ملف DMG وقراءة الملف التمهيدي.

كتابة رمز


بعد إعداد SDL_image ، نبدأ في كتابة التعليمات البرمجية. أولاً ، كما هو الحال دائمًا ، سنقوم بتوصيل المكتبات ، وتعيين أحجام النوافذ وإنشاء 3 متغيرات عامة.

 #include <SDL2/SDL.h> #include <SDL2/SDL_image.h> #include <iostream> const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; SDL_Window *win = NULL; SDL_Surface *scr = NULL; SDL_Surface *flower = NULL; 

لاحظ أنني قمت بتوصيل SDL_image.h بشكل منفصل ، حيث إنها مكتبة منفصلة.

بعد ذلك ، نكتب 3 وظائف ، معروفة لنا ، والتي سنقوم بإضافة شيء وتغييره ، كالمعتاد.

أولي ()
 bool init() { if (SDL_Init(SDL_INIT_VIDEO) != 0) { std::cout << "Can't init video: " << SDL_GetError() << std::endl; return false; } int flags = IMG_INIT_PNG; if ( !( IMG_Init( flags ) & flags ) ) { std::cout << "Can't init image: " << IMG_GetError() << std::endl; return false; } win = SDL_CreateWindow(" PNG", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN); if (win == NULL) { std::cout << "Can't create window: " << SDL_GetError() << std::endl; return false; } scr = SDL_GetWindowSurface(win); return true; } 


أضفنا هنا تهيئة وحدة SDL_image. لتهيئته ، قم أولاً بإنشاء متغير int ، ولدينا إشارات ، وحفظ كل العلامات التي تريد استخدامها للتهيئة.

قائمة بجميع الأعلام
SDL_INIT_PNG - تهيئة برنامج تنزيل صور PNG ؛
SDL_INIT_JPG - تهيئة برنامج تنزيل صور JPG ؛
SDL_INIT_TIF - تهيئة برنامج تنزيل الصور TIF ؛

بعد ذلك ، نكتب هذا الشرط:

 if ( !( IMG_Init( flags ) & flags ) ) 

ترجع الدالة IMG_Init () الإشارات التي تمكنت من التهيئة. إذا أعادت الأعلام ، لكن العلامة التي أردناها كانت مفقودة ، سنرجع خطأً. بسيط جدا لاحظ أيضًا أنني أستخدم IMG_GetError بدلاً من SDL_GetError ، نظرًا لأننا نبحث عن خطأ في وظيفة الوحدة النمطية SDL_image ، وليس SDL .

أريد أيضًا أن أشير إلى أنني قررت استخدام نوع منطقي لإرجاع - هذه طريقة أكثر عقلانية.

دعنا نواصل كتابة برنامجنا ، وكتابة وظيفة Load () ، التي نحمل فيها صورة PNG ونحولها.

حمل
 bool load() { flower = IMG_Load("flower.png"); if (flower == NULL) { std::cout << "Can't load: " << IMG_GetError() << std::endl; return false; } flower = SDL_ConvertSurface(flower, scr->format, NULL); if (flower == NULL) { std::cout << "Can't convert: " << SDL_GetError() << std::endl; return false; } return true; } 


نحن هنا نقوم بتحميل الصورة باستخدام وظيفة IMG_Load الجديدة. وظيفتها هي نفسها وظيفة SDL_LoadBMP والنتيجة هي نفسها - تقوم بإرجاع مثيل لفئة SDL_Surface . للعثور على أخطاء أثناء التحميل ، نستخدم أيضًا IMG_GetError .

حان الوقت لتحويل. أولاً ، نظرية صغيرة. قلة من الناس يعرفون ، لكن عند تنزيل صورة ، يتم تنزيلها بتنسيق 24 بت ، ومعظم شاشات العرض الحديثة بتنسيق 32 بت. وفي كل مرة نعرض فيها الصورة على الشاشة ، تمت إعادة بنائها لأول مرة بتنسيق 32 بت. بالنسبة للبرامج البسيطة ، لا يهم هذا الأمر ، ولكن عند إنشاء نوع من المشاريع الكبيرة ، سيؤثر ذلك بشكل كبير على الأداء ، لذلك سنتخذها وفي مرحلة تحميل الصور ، سنقوم بإعادة تشكيلها بتنسيق العرض. سوف تساعد وظيفة SDL_ConvertSurface . يستغرق 3 قيم: السطح الذي نريد تنسيقه ، التنسيق الذي نريد تنسيقه ، والأعلام. نريد تنسيق صورة الزهرة ، ونمرّرها المعلمة الأولى. المعلمة الثانية هي شكل سطح النافذة ، ونحن لن نستخدم الأعلام. هذه الوظيفة تقوم بإرجاع نسخة من السطح ، والتي نقوم بتعيينها على الفور للزهرة . للبحث عن الأخطاء ، نأخذ وظيفة SDL_GetError () ، لأننا نعمل بالفعل مع الأسطح ، وهم من SDL ، وليس من SDL_image .

بعد ذلك نكتب وظيفة Quit ، أضف وظيفة واحدة فقط إليها.

استقال
 void quit() { SDL_FreeSurface(flower); SDL_FreeSurface(scr); SDL_DestroyWindow(win); SDL_Quit(); IMG_Quit(); } 


أضفنا IMG_Quit لإلغاء تهيئة وحدة SDL_image.

رئيسي


الآن يبقى أبسط شيء - الوظيفة الرئيسية .

 int main (int argc, char ** args) { if (!init()) { system("pause"); quit(); return 1; } if (!load()) { system("pause"); quit(); return 1; } 

للبدء ، تهيئة وإنشاء كل ما تحتاجه وتحميل الملفات الضرورية. لن نتوقف هنا.

  SDL_Rect bg_flower; bg_flower.w = SCREEN_WIDTH; bg_flower.h = SCREEN_HEIGHT; bg_flower.x = 0; bg_flower.y = 0; 

بعد ذلك ، قم بإنشاء كائن للفئة SDL_Rect . سنحتاجه لتمديد الصورة. إذا لاحظت ، تكون صورة الزهرة أصغر من حجم النافذة بأربعة أضعاف (أرق مرتين وأقل مرتين) ، ونحن بحاجة إلى مدها إلى حجم النافذة. حتى في عرض المستطيل bg_flower اكتب قيمة عرض النافذة ، وفي الارتفاع - ارتفاع النافذة. اضبط الإحداثيات على 0 ، بحيث يتم عرض الصورة في الزاوية اليسرى العليا.

لعرض الصور مع تغيير حجمها ، هناك وظيفة خاصة. يبدو مثل هذا:

  SDL_BlitScaled(flower, NULL, scr, &bg_flower); 

يستغرق 4 معاني. الأول هو الصورة التي نريد عرضها ، والثاني هو المستطيل الذي نريد قصه من هذه الصورة (إذا أردنا التقاط الصورة بأكملها ، نكتب NULL) ، والثالث هو السطح الذي نريد أن نعرض عليه الصورة ، والرابع هو نفس المستطيل ، الأبعاد والإحداثيات التي نأخذها لتمديد أو ضغط وعرض الصورة.

بعد ذلك ، فقط قم بتحديث سطح الشاشة ، واضبط التأخير والخروج والعودة 0.

  SDL_UpdateWindowSurface(win); SDL_Delay(2000); quit(); return 0; }; 

هذا هو المكان الذي ينتهي فيه برنامجنا. من أجل ترجمة هذه المعجزة ، تحتاج إلى إضافة -lSDL2_image ، كخيار تجميع آخر.

وعلى هذا سننتهي لهذا اليوم. إليك الكود الذي حصلنا عليه:

 #include <SDL2/SDL.h> #include <SDL2/SDL_image.h> #include <iostream> const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; SDL_Window *win = NULL; SDL_Surface *scr = NULL; SDL_Surface *flower = NULL; bool init() { if (SDL_Init(SDL_INIT_VIDEO) != 0) { std::cout << "Can't init video: " << SDL_GetError() << std::endl; return false; } int flags = IMG_INIT_PNG; if ( !( IMG_Init( flags ) & flags ) ) { std::cout << "Can't init image: " << IMG_GetError() << std::endl; return false; } win = SDL_CreateWindow(" PNG", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN); if (win == NULL) { std::cout << "Can't create window: " << SDL_GetError() << std::endl; return false; } scr = SDL_GetWindowSurface(win); return true; } bool load() { flower = IMG_Load("flower.png"); if (flower == NULL) { std::cout << "Can't load: " << IMG_GetError() << std::endl; return false; } flower = SDL_ConvertSurface(flower, scr->format, NULL); if (flower == NULL) { std::cout << "Can't convert: " << SDL_GetError() << std::endl; return false; } return true; } void quit() { SDL_FreeSurface(flower); SDL_FreeSurface(scr); SDL_DestroyWindow(win); SDL_Quit(); IMG_Quit(); } int main (int argc, char ** args) { if (!init()) { system("pause"); quit(); return 1; } if (!load()) { system("pause"); quit(); return 1; } SDL_Rect bg_flower; bg_flower.w = SCREEN_WIDTH; bg_flower.h = SCREEN_HEIGHT; bg_flower.x = 0; bg_flower.y = 0; SDL_BlitScaled(flower, NULL, scr, &bg_flower); SDL_UpdateWindowSurface(win); SDL_Delay(2000); quit(); return 0; }; 

وداعا للجميع!

<< الدرس السابق || الدرس القادم >>

Source: https://habr.com/ru/post/ar456656/


All Articles