سؤال

لقد كنت أحاول عرض النص على نافذة openGL باستخدام SDL ومكتبة SDL_TTF على نظام التشغيل Windows XP، VS2010.
الإصدارات:
إصدار SDL 1.2.14
تطوير SDL TTF 1.2.10
openGL (الإصدار لا يقل عمره عن 2-3 سنوات).

لقد نجحت في إنشاء نافذة openGL باستخدام SDL / SDL_image ويمكنني عرض الخطوط / المضلعات عليها دون أي مشاكل.

ومع ذلك، عند الانتقال إلى النص، يبدو أن هناك بعض الخلل في برنامجي الحالي، وأحصل على النتيجة التالية عند المحاولة هذا الرمز هنا

enter image description here

بالنسبة لأولئك الذين لا يرغبون في اللصق، إليك فقط مقاطع التعليمات البرمجية الحاسمة:

void drawText(char * text) {
    glLoadIdentity();
    SDL_Color clrFg = {0,0,255,0}; // set colour to blue (or 'red' for BGRA)
    SDL_Surface *sText = TTF_RenderUTF8_Blended( fntCourier, text, clrFg );
    GLuint * texture = create_texture(sText);
    glBindTexture(GL_TEXTURE_2D, *texture);
    // draw a polygon and map the texture to it, may be the source of error
    glBegin(GL_QUADS); {
        glTexCoord2i(0, 0); glVertex3f(0, 0, 0);
        glTexCoord2i(1, 0); glVertex3f(0 + sText->w, 0, 0);
        glTexCoord2i(1, 1); glVertex3f(0 + sText->w, 0 + sText->h, 0);
        glTexCoord2i(0, 1); glVertex3f(0, 0 + sText->h, 0);
    } glEnd();
    // free the surface and texture, removing this code has no effect
    SDL_FreeSurface( sText );
    glDeleteTextures( 1, texture );
}

الجزء 2:

// create GLTexture out of SDL_Surface
GLuint * create_texture(SDL_Surface *surface) {
    GLuint texture = 0;

    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    // The SDL_Surface appears to have BGR_A formatting, however this ends up with a 
    // white rectangle no matter which colour i set in the previous code.
    int Mode = GL_RGB;

    if(surface->format->BytesPerPixel == 4) {
        Mode = GL_RGBA;
    }

    glTexImage2D(GL_TEXTURE_2D, 0, Mode, surface->w, surface->h, 0, Mode, 
                 GL_UNSIGNED_BYTE, surface->pixels);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    return &texture;
}

هل هناك جزء واضح من الكود الذي أفتقده؟
شكرا لك على أي مساعدة حول هذا الموضوع.
لقد كنت أحاول تعلم openGL وSDL لمدة 3 أيام حتى الآن، لذا يرجى أن تغفر لي أي معلومات خاطئة من جهتي.


يحرر:

ألاحظ أن استخدام
TTF_RenderUTF8_Shaded
TTF_RenderUTF8_Solid

قم بإلقاء استثناء مؤشر فارغ، مما يعني أن هناك خطأ في وظيفة عرض النص الفعلية (أظن)، لا أعرف كيف يعني ذلك TTF_RenderUTF8_Blended تقوم بإرجاع مربع أحمر ولكني أظن أن كل المشاكل تتوقف على هذا.

هل كانت مفيدة؟

المحلول

أعتقد أن المشكلة في glEnable(GL_TEXTURE_2D) و glDisable(GL_TEXTURE_2D) الوظائف التي يجب استدعاؤها في كل مرة يتم فيها رسم النص على الشاشة. وربما يكون أيضًا تحويل الألوان بين سطح SDL وGL غير صحيح.لقد جمعت create_texture و drawText في وظيفة واحدة تعرض النص بشكل صحيح.هذا هو الرمز:

void drawText(char * text, TTF_Font* tmpfont) {
SDL_Rect area;
SDL_Color clrFg = {0,0,255,0};
SDL_Surface *sText = SDL_DisplayFormatAlpha(TTF_RenderUTF8_Blended( tmpfont, text, clrFg ));
area.x = 0;area.y = 0;area.w = sText->w;area.h = sText->h;
SDL_Surface* temp = SDL_CreateRGBSurface(SDL_HWSURFACE|SDL_SRCALPHA,sText->w,sText->h,32,0x000000ff,0x0000ff00,0x00ff0000,0x000000ff);
SDL_BlitSurface(sText, &area, temp, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sText->w, sText->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp->pixels);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS); {
    glTexCoord2d(0, 0); glVertex3f(0, 0, 0);
    glTexCoord2d(1, 0); glVertex3f(0 + sText->w, 0, 0);
    glTexCoord2d(1, 1); glVertex3f(0 + sText->w, 0 + sText->h, 0);
    glTexCoord2d(0, 1); glVertex3f(0, 0 + sText->h, 0); 
} glEnd();
glDisable(GL_TEXTURE_2D);
SDL_FreeSurface( sText );
SDL_FreeSurface( temp );
} 

لقطة شاشة

أقوم بتهيئة OpenGL كما يلي:

int Init(){
glClearColor( 0.1, 0.2, 0.2, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho( 0, 600, 300, 0, -1, 1 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if( glGetError() != GL_NO_ERROR ){
    return false;
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA);
} 

نصائح أخرى

أعتقد أنه يجب عليك فقط إضافة glEnable(GL_BLEND)، لأن رمز سطح النص يقول TTF_RenderUTF8_Blending( fntCourier, text, clrFg ) ويجب عليك تمكين قدرات المزج لـ opengl.

يحرر

حسنًا، أخيرًا، أخذت الوقت الكافي لوضع التعليمات البرمجية الخاصة بك من خلال مترجم.والأهم من ذلك، المترجم مع -Werror بحيث يتحول التحذير إلى أخطاء

GLuint * create_texture(SDL_Surface *surface) {
    GLuint texture = 0;

    /*...*/

    return &texture;
}

لم أره أولاً، لأن هذا يشبه برنامج C Coder's 101 وهو أمر غير متوقع تمامًا: يجب ألا تعيد المؤشرات إلى المتغيرات المحلية!.بمجرد خروج الوظائف من النطاق، سيشير المؤشر الذي تم إرجاعه إلى هراء فقط.لماذا تقوم بإرجاع المؤشر على الإطلاق؟فقط قم بإرجاع عدد صحيح:

GLuint create_texture(SDL_Surface *surface) {
    GLuint texture = 0;

    /*...*/

    return texture;
}

ولهذا السبب، لن تقوم أيضًا بحذف النسيج بعد ذلك.يمكنك تحميله إلى OpenGL، ولكن بعد ذلك تفقد الإشارة إليه.


يفتقد الرمز الخاص بك أ glEnable(GL_TEXTURE_2D) ولهذا السبب لا يمكنك رؤية أي آثار للملمس. لكن استخدامك للقوام هو دون المستوى الأمثل.بالطريقة التي فعلت بها ذلك، يمكنك إعادة إنشاء نسيج جديد تمامًا في كل مرة تكون على وشك رسم هذا النص.إذا حدث ذلك في حلقة الرسوم المتحركة، فسوف

  1. نفاد ذاكرة الملمس قريبًا
  2. إبطائه بشكل ملحوظ

(1) يمكن معالجتها من خلال عدم إنشاء اسم نسيج جديد في كل عملية إعادة رسم

(2) يمكن العناوين عن طريق تحميل بيانات نسيج جديدة فقط عندما يتغير النص وعدم استخدام glTexImage2D، بل glTexSubImage2D (بالطبع، إذا تغيرت أبعاد النسيج، فيجب أن يكون glTexImage2D).


تحرير، وجدت مشكلة أخرى محتملة، ولكن قم أولاً بإصلاح مشكلة المؤشر لديك.

يجب عليك التأكد من أنك تستخدم وضع بيئة النسيج GL_REPLACE أو GL_MODULATE.إذا كنت تستخدم GL_DECAL أو GL_BLEND، فسينتهي بك الأمر بنص أحمر على مربع أحمر.

كان هناك تسرب في ذاكرة الوظيفة في رسالتي السابقة وكان البرنامج يتعطل بعد مرور بعض الوقت ...لقد قمت بتحسين هذا عن طريق فصل تحميل النسيج وعرضه:

يجب استدعاء الوظيفة الأولى قبل حلقة SDL. وهي تقوم بتحميل سلسلة نصية في الذاكرة:

يجب أن تحتوي كل سلسلة يتم تحميلها على معلمة txtNum مختلفة

GLuint texture[100];
SDL_Rect area[100]; 
void Load_string(char * text, SDL_Color clr, int txtNum, const char* file, int ptsize){
    TTF_Font* tmpfont;
    tmpfont = TTF_OpenFont(file, ptsize); 
    SDL_Surface *sText = SDL_DisplayFormatAlpha(TTF_RenderUTF8_Solid( tmpfont, text, clr ));
    area[txtNum].x = 0;area[txtNum].y = 0;area[txtNum].w = sText->w;area[txtNum].h = sText->h;
    glGenTextures(1, &texture[txtNum]);
    glBindTexture(GL_TEXTURE_2D, texture[txtNum]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, sText->w, sText->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, sText->pixels);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    SDL_FreeSurface( sText );
    TTF_CloseFont(tmpfont);
 }

يعرض الثاني السلسلة، التي يجب استدعاؤها في حلقة SDL:

void drawText(float coords[3], int txtNum) {
     glBindTexture(GL_TEXTURE_2D, texture[txtNum]);
     glEnable(GL_TEXTURE_2D);
     glBegin(GL_QUADS); {
     glTexCoord2f(0, 0); glVertex3f(coords[0], coords[1], coords[2]);
     glTexCoord2f(1, 0); glVertex3f(coords[0] + area[txtNum].w, coords[1], coords[2]);
     glTexCoord2f(1, 1); glVertex3f(coords[0] + area[txtNum].w, coords[1] + area[txtNum].h, coords[2]);
     glTexCoord2f(0, 1); glVertex3f(coords[0], coords[1] + area[txtNum].h, coords[2]); 
     } glEnd();
     glDisable(GL_TEXTURE_2D);
}

enter image description here

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top