简体   繁体   中英

Display images on a transparent background with no border in C++ / OpenGL

I am looking for a way to display two png images (in fact, it will be numbers, my aim is to create an overlay for live streaming to display players score and some further additional content) on a window with transparent background with no border. So that we just see the score over the window placed behind.

Is there any way to do something like that ? I have already tried many things with SDL, textures, but nothing led me to any satisfying result. The best I found was some dirty code almost working but completely unusable.

If possible, the solution may let possible to add the functionality that when you click left or right on one of the 2 scores, it is incremented or decremented.

Edit: Here is my current code. I started new without any bit of the dirty code I had before, because I would like to understand what I am doing. I have my 2 numbers displayed as textures, now I would like to remove borders and title bar of my window, and make my background transparent.

#include <stdio.h>
#include <stdlib.h>

#include <iostream>
#include <windows.h>
#include <windowsx.h>
#include <math.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#include "sdlglutils.h"

#include <assert.h>
#include <tchar.h>

using namespace std;

int overlay;
int TimerEnabled;
GLfloat posX, posY, posZ;
GLuint texture_0, texture_1, texture_2, texture_3;

void Initialize()
{
    glEnable(GL_ALPHA_TEST);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_COLOR_MATERIAL);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glClearColor(0, 0, 0, 0);

    glEnable(GL_TEXTURE_2D);
}

void Reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei) w, (GLsizei) h);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f, (GLfloat)w/(GLfloat)h,0.1f,100.0f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    texture_0 = loadTexture("0.png");
    texture_1 = loadTexture("1.png");
    texture_2 = loadTexture("2.png");
    texture_3 = loadTexture("3.png");

    return;
}

void Draw()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

    glTranslatef(posX,posY,posZ);

    glScalef(1.0f,1.0f,1.0f);
    glPushMatrix();
        glTranslated(-6, 8, 0);
        glBindTexture(GL_TEXTURE_2D, texture_1);
        glBegin(GL_QUADS);
            glTexCoord2d(0,0);      glVertex2d(0,0);
            glTexCoord2d(1,0);      glVertex2d(1,0);
            glTexCoord2d(1,1);      glVertex2d(1,1);
            glTexCoord2d(0,1);      glVertex2d(0,1);
        glEnd();
    glPopMatrix();

    glPushMatrix();
        glTranslated(6, 8, 0);
        glBindTexture(GL_TEXTURE_2D, texture_2);
        glBegin(GL_QUADS);
            glTexCoord2d(0,0);      glVertex2d(0,0);
            glTexCoord2d(1,0);      glVertex2d(1,0);
            glTexCoord2d(1,1);      glVertex2d(1,1);
            glTexCoord2d(0,1);      glVertex2d(0,1);
        glEnd();
    glPopMatrix();

    glFlush();
}

void Display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    Draw();

    glutSwapBuffers();
}

void KeyboardSpecialEvent( int key, int x, int y)
{
    switch(key)
    {
        case(GLUT_KEY_UP) :
        {
            posY += 0.3;
        }break;

        case(GLUT_KEY_DOWN) :
        {
            posY -= 0.3;
        }break;

        case(GLUT_KEY_LEFT) :
        {
            posX -= 0.3;
        }break;

        case(GLUT_KEY_RIGHT) :
        {
            posX += 0.3;
        }break;
    }
}
void MouseEvent( int button, int state, int x, int y){ };
void MotionMouseEvent( int x, int y ){  };
void IdleEvent(){  };
void TimerEvent(int time)
{
    glutPostRedisplay();

    if(TimerEnabled)
        glutTimerFunc(10, TimerEvent, time);
}

void KeyboardEvent( unsigned char key, int x, int y)
{
    switch(key)
    {
        case ' ' :
        {
            TimerEnabled = !TimerEnabled;
            if (TimerEnabled)
                glutTimerFunc(40, TimerEvent, 0);
        }
        break;

        case 'q' :
        {
            exit(0);
        }
        break;
    }
}

int main(int argc, char** argv)
{
    posX = 0;
    posY = 0;
    posZ = -25;
    TimerEnabled = 1;

    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_RGBA);

    glutInitWindowSize(1600,900);
    glutInitWindowPosition(0,0);

    overlay = glutCreateWindow("ScoreOverlay");
    //glutFullScreen();

    Initialize();

    glutDisplayFunc(Display);
    glutReshapeFunc(Reshape);
    glutKeyboardFunc(KeyboardEvent);
    glutSpecialFunc(KeyboardSpecialEvent);
    glutMouseFunc(MouseEvent);
    glutMotionFunc(MotionMouseEvent);
    glutIdleFunc(IdleEvent);
    glutTimerFunc(40, TimerEvent, 0);

    glutMainLoop();

    return 0;
}

Here is a working base sample (using c++ with clr support) that could help you.

You need to adapt it to your need (for example use DrawImage instead of FillEllipse)

using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;

ref class MyForm : public Form
{
public:

    MyForm()
    {
        this->m_brush = gcnew SolidBrush(Color::Blue);

        this->m_canvas = gcnew System::Windows::Forms::Panel();
        this->m_canvas->BackColor = Color::Pink;
        this->m_canvas->Dock = System::Windows::Forms::DockStyle::Fill;
        this->m_canvas->Location = System::Drawing::Point(0, 0);
        this->m_canvas->Margin = System::Windows::Forms::Padding(0);
        this->m_canvas->Name = "Canvas";
        this->m_canvas->Paint += gcnew System::Windows::Forms::PaintEventHandler(this, &MyForm::canvas_Paint);
        this->m_canvas->TabIndex = 0;

        this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
        this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
        this->BackColor = Color::Pink;
        this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::None;
        this->ClientSize = System::Drawing::Size(200, 200);
        this->Controls->Add(this->m_canvas);
        this->KeyDown += gcnew System::Windows::Forms::KeyEventHandler(this, &MyForm::form_KeyDown);
        this->TransparencyKey = Color::Pink;
        this->Name = "MyForm";
        this->Text = "MyForm";
    }

private:

    void canvas_Paint(Object^ sender, PaintEventArgs^ e) {
        e->Graphics->FillEllipse(this->m_brush, Rectangle(50, 50, 100, 100));
    }

    void form_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) {
        // Test key ...
        this->m_canvas->Invalidate();
        // ...
    }

    Brush^ m_brush;
    Panel^ m_canvas;
};

[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
    // Enabling Windows XP visual effects before any controls are created
    Application::EnableVisualStyles();
    Application::SetCompatibleTextRenderingDefault(false); 

    // Create the main window and run it
    Application::Run(gcnew MyForm());
    return 0;
}

It looks like you need this on Windows. Have you looked at Layered Windows ?

Unless you need OpenGL for the graphics for some reason I think you'll be better off loading your images as regular bitmaps and blitting them to the layered window directly. Using OpenGL you would need to draw to a texture map, then take that texture and blit it to the layered window.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM