vegastrike / Vega-Strike-Engine-Source

Vega Strike Engine
Other
255 stars 44 forks source link

0.7.0 won't run on Ubuntu 20.04 -- throws exception when glGetString(GL_RENDERER) returns NULL. #554

Closed monohydroxy closed 2 years ago

monohydroxy commented 3 years ago

I installed the VegaStrike engine and the UTCS data from the released packages. When I start the engine (pointed at the data directory) it will switch graphics modes, then throw an exception and crash.

I debugged it a bit and the crash is because the glGetString(GL_RENDERER) returns NULL in the winsys.cpp file. Unfortunately, I don't know enough about SDL/GL to debug any further. FYI, glxgears runs without issues.

The system is a desktop running Ubuntu 20.04 and a Radeon RX 570 GPU.

Here is what is printed on startup.

[2021-09-14 17:23:45.523463] [0x00007fba3b66f900] [trace]   Registering codec ogg
[2021-09-14 17:23:45.523480] [0x00007fba3b66f900] [trace]   .
Legacy Mode: FALSE
 In path /home/user/Games/Vega-Strike-Engine-Source/bin
Vega Strike  
See http://www.gnu.org/copyleft/gpl.html for license details.

ARG #1 = -D/home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/
Using data dir specified on command line : /home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/
GOT SUBDIR ARG = 
Found data in /home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/
Using /home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike as data directory
Using .vegastrike as the home directory
Found MODDIR = /home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/mods
USING HOMEDIR : /home/user/.vegastrike As the home directory 
CONFIGFILE - Found a config file in home directory, using : /home/user/.vegastrike/vegastrike.config
DATADIR - No datadir specified in config file
Force galaxy to /home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/universe/milky_way.xml
SIMULATION_ATOM: 0.01
log directory : '/home/user/.vegastrike/logs'
['/opt/anaconda3/lib/python38.zip', '/opt/anaconda3/lib/python3.8', '/opt/anaconda3/lib/python3.8/lib-dynload']
['', '/home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/modules/builtin', '/home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/modules/quests', '/home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/modules/missions', '/home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/modules/ai', '/home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/modules', '/home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/bases', '/opt/anaconda3/lib/python38.zip', '/opt/anaconda3/lib/python3.8', '/opt/anaconda3/lib/python3.8/lib-dynload']
terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_M_construct null not valid
Aborted (core dumped)
stephengtuggy commented 3 years ago

@monohydroxy thanks for reporting this issue.

Is there a log file in /home/user/.vegastrike/logs that you can attach to this ticket? Also, what do you get when you run the following in the terminal?

glxinfo | grep "OpenGL version"
monohydroxy commented 3 years ago

glxinfo says: OpenGL version string: 4.6 (Compatibility Profile) Mesa 20.1.6 and the logs directory is empty, which is strange because it gets to the InitLogging code (part 1 and part 2).

stephengtuggy commented 3 years ago

glxinfo says: OpenGL version string: 4.6 (Compatibility Profile) Mesa 20.1.6 and the logs directory is empty, which is strange because it gets to the InitLogging code (part 1 and part 2).

Hmm. That is slightly odd.

Can you rerun the game with --debug=3? Then check the logs directory again?

monohydroxy commented 3 years ago

--debug=3 gives me the following in the log file:


[2021-09-14 20:09:21.690272]: Opening CSV database from 'units.csv'
[2021-09-14 20:09:21.690379]: Loading CSV database from 'units.csv'
[2021-09-14 20:09:21.694967]: Opening CSV database from 'units_description.csv'
[2021-09-14 20:09:21.695027]: Loading CSV database from 'units_description.csv'
[2021-09-14 20:09:21.695493]:   Textual_Description (1) -> 6
[2021-09-14 20:09:21.695501]:    (0) -> 0
[2021-09-14 20:09:21.695506]: Reshaped table holds 89037 cells
[2021-09-14 20:09:21.695514]: Merging rows...
[2021-09-14 20:09:21.696246]: Rows Merged: 281, Rows Added: 446
[2021-09-14 20:09:21.696255]: Merged table holds 141219 cells
[2021-09-14 20:09:21.703183]: running import sys
print(sys.path)
sys.path = ["",r"/home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/modules/builtin",r"/home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/modules/quest\
s",r"/home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/modules/missions",r"/home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/modules/ai",r"/home/user\
/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/modules",r"/home/user/Games/VegaStrike-UTCS-0.7.1/usr/share/vegastrike/bases"] + sys.path
[2021-09-14 20:09:21.703384]: testing VS random
[2021-09-14 20:09:21.703393]: running import sys
print(sys.path)
[2021-09-14 20:09:21.924935]: Creating scene manager...
[2021-09-14 20:09:21.925031]:   Initializing renderer...```
stephengtuggy commented 3 years ago

The line of code in question probably needs to be changed from:

    std::string version = (const char*)glGetString(GL_RENDERER);

to:

    const char *glVersionTmp = (const char*)glGetString(GL_RENDERER);
    if (glVersionTmp == nullptr) {
        // Handle error
    } else {
        std::string version = glVersionTmp;
        // ...
    }
stephengtuggy commented 3 years ago

We may also need to flush the logs after the previous code section, to make sure we're getting all the logging output.

stephengtuggy commented 3 years ago

This issue reminds me very much of https://github.com/vegastrike/Vega-Strike-Engine-Source/issues/418 . In fact, I wonder if they are the same basic issue.

monohydroxy commented 3 years ago

I found a work-around. If I change the CMakeLists.txt file to link with GL before the OpenGL library it works. TARGET_LINK_LIBRARIES(vegastrike-engine GL ${TST_LIBS} ) I don't know cmake, so I'm not sure the proper way to do this and I don't know OpenGL, so I don't know why it works. :)

Thanks for your help on this issue.

stephengtuggy commented 3 years ago

@monohydroxy Hmm, very interesting. Thanks for the update.

BenjamenMeyer commented 3 years ago

@monohydroxy CMake doesn't determine dependency orders so if a dependency needs to be linked earlier it has to either:

The first is what you did, and is the simplest solution. The second is harder to do and is very compiler dependent; usually you only do that if you have cyclic dependencies being linked.

So why does the first one work? It's probably b/c we have the TST_LIBS ordering incorrectly somewhere.

Basically, the libraries need to be ordered left to right based on dependency. The left most needs to have no dependency, while the right most can depend on everything left of it. The link groups (mentioned above) breaks the ordering so that something on the left can depend on something on the right within the group.

Looking at https://github.com/vegastrike/Vega-Strike-Engine-Source/blob/master/engine/CMakeLists.txt#L1184 it seems we got an ordering out of order:

#Setup shared lib and include listings for vegastrike-engine.
SET(TST_LIBS vegastrike-engine_com vegastrike-OPcollide ${TST_LIBS})

That is, the vegastrike-engine_com and vegastrike-OPcollide likely depend on something in TST_LIBS, so they should be to the right of TST_LIBS not the left.

Try changing that line without your change in TARGET_LINK_LIBRARIES (a few lines later) and see if that works. If it does, then please submit a PR; you can do so against master and we'll help you port it to 0.7.x for a point release.

monohydroxy commented 3 years ago

I changed it to: SET(TST_LIBS ${TST_LIBS} vegastrike-engine_com vegastrike-OPcollide) But I get some error messages as per below. These seem to mean something is in the wrong order. /usr/bin/ld: /usr/lib/x86_64-linux-gnu/libpython3.8.so: undefined reference to symbol 'inflateEnd' /usr/bin/ld: /usr/lib/x86_64-linux-gnu/libz.so: error adding symbols: DSO missing from command line

monohydroxy commented 3 years ago

I changed it to: SET(TST_LIBS ${TST_LIBS} vegastrike-engine_com vegastrike-OPcollide) But I get some error messages as per below. These seem to mean something is in the wrong order. /usr/bin/ld: /usr/lib/x86_64-linux-gnu/libpython3.8.so: undefined reference to symbol 'inflateEnd' /usr/bin/ld: /usr/lib/x86_64-linux-gnu/libz.so: error adding symbols: DSO missing from command line

I also tried uninstalling the AMD GPU driver and then it also worked. When I updated to the latest version it didn't work any more. This looks like a driver issue on my side. :(

stephengtuggy commented 3 years ago

I don't think it's a driver issue per se, since at least one other person has encountered a similar issue. Instead, I think it might be that our code is not smart enough to link to the AMD driver's GL implementation, as opposed to the Mesa OpenGL implementation. This might be tricky to fix. I'll have to see what we can do.

stephengtuggy commented 3 years ago

OK. So based on what I'm reading, we should be using GLVND for a vendor-independent OpenGL wrapper (when on Linux specifically.) To use this, we should use CMake target variable OpenGL::GL, and make sure that OpenGL_GL_PREFERENCE is set to GLVND. Which it should be already, since policy CMP0072 is automatically set to NEW when we require CMake 3.11 as our minimum supported CMake version.

See https://cmake.org/cmake/help/v3.21/module/FindOpenGL.html#linux-specific and https://cmake.org/cmake/help/v3.21/policy/CMP0072.html#policy:CMP0072

But the above only applies to master / 0.9.x, since that is where we have moved to requiring CMake 3.11. With older CMake versions, we're not guaranteed to have any of the above functionality. As far as I can tell, anyway.

monohydroxy commented 2 years ago

If I add a line like the following to CMakeLists.txt then it links with GL (not OpenGL) and it works. My cmake is version 3.16.3. SET(OpenGL_GL_PREFERENCE "LEGACY")

Below is my mini test case where the link library determines if we can get the GL_RENDERER value or not.


// Two ways to build, OpenGL doesn't work, but GL does work.
//  The failing case is only when the proprietary AMD GPU driver is installed.
// g++ test.cpp -o testbad  -lOpenGL -lGLU -lSDL
// g++ test.cpp -o testgood -lGL     -lGLU -lSDL

#include <stdio.h>
#include <SDL/SDL.h>
#include <GL/glut.h>

int main()
{
    SDL_Init( SDL_INIT_VIDEO );
    SDL_SetVideoMode( 1920, 1080, 32, SDL_OPENGL | SDL_FULLSCREEN );

    const unsigned char * tmp = glGetString(GL_RENDERER);
    if (tmp == NULL)
    {
        printf ("CAN'T DETERMINE RENDERER\n"); // Links with OpenGL
        SDL_Quit();
        return false;
    }
    else
    {
        printf ("%s\n", (const char *) tmp); // Links with GL
        SDL_Quit();
        return true;
    }
}
stephengtuggy commented 2 years ago

@monohydroxy That's some good test code. Thanks for that.

stephengtuggy commented 2 years ago

We're discussing this on Gitter at the moment: https://gitter.im/vegastrike/community

monohydroxy commented 2 years ago

Here is an interesting finding, but I'm no closer to understanding it. If I use SDL_GL_GetProcAddress() to get a function pointer to glGetString(), then it always works. If I call glGetString() directly, then it doesn't work. Somehow these seem to be calling two different functions.

#include <stdio.h>
#include <SDL/SDL.h>
#include <GL/glut.h>

int main()
{
    SDL_Init( SDL_INIT_VIDEO );

    SDL_SetVideoMode( 100, 100, 32, SDL_OPENGL );

    const unsigned char * rend = (const unsigned char *) glGetString(GL_RENDERER);
    if (rend == NULL)
    {
        printf ("RENDERER is NULL\n"); // Link with OpenGL
    }
    else
    {
        printf ("RENDERER: %s\n", rend); // Link with GL
    }

    // Ugly function point.
    char * (*cal) (int) = (char * (*) (int)) SDL_GL_GetProcAddress("glGetString");
    char * r = cal(GL_RENDERER);
    printf ("RENDERER (with getProcAddr): %s\n", r); // Always works.

    printf ("0x%lx == 0x%lx\n", (long) cal, (long) glGetString);

    SDL_Quit();
}
BenjamenMeyer commented 2 years ago

@monohydroxy yes, SDL_GL_GetProcAddress is probably doing a dynamic lookup to get the appropriate function. We probably should be doing something of that nature to ensure we get the right one. Not sure if GLVND would be doing that for us or not. So there's a bug that we can solve this with.

stephengtuggy commented 2 years ago

@monohydroxy I adapted your latest code slightly, and incorporated it into the proper section of code in engine/src/gldrv/winsys.cpp. Not sure if this will be a complete fix, but I'm curious to see what kinds of results you get testing this code.

stephengtuggy commented 2 years ago

(See the above draft Pull Request, #555 )

monohydroxy commented 2 years ago

This is only half a thought, but I wanted to share it: The SDL 1.2 library seems to have a hard coded default of libGL.so to look up 'proc addresses' (https://github.com/libsdl-org/SDL-1.2/blob/27d991f356a2712feba0d7749f11807849665491/src/video/x11/SDL_x11gl.c#L31). This seems to completely bypass the libOpenGL.so library. As I understand libOpenGL.so is just a wrapper with a bunch of pointers to the real GL library, based on the current context. Maybe libOpenGL never learns the current context and thus never creates the link from OpenGL to GL, so a direct OpenGL call to glGetString() will just return immediately because there is no function to call.

So I like your Pull Request #555 because it routes everything through the same interface (SDL) to get at the OpenGL stuff. I'm not sure if this breaks down elsewhere so I guess we'll see.

I'm pretty ignorant of SDL 1.2 vs 2.0, but would a better long term solution be to move to SDL 2.0? I'm guessing that is a huge amount of work or someone would have done it already. :)

Loki1950 commented 2 years ago

Indeed SDL 2.0 would be much better it handles multi-screen setups more gracefully even the sound calls a cleaner but as you mentioned lots of grunt work.

monohydroxy commented 2 years ago

Here is a small example of a way to proceed. The two tricks I've found are:

  1. All glXxx() calls must be from a SDL_GL_GetProcAddress(). See the ugly #define's at the top of the code below.
  2. glu functions must not be used. In the example below I had to replace gluPerspective() with a function that calls glFrustum().

The example code below was taken from a SDL Open GL example I found on the internet. The gluPerspective replacement function is similarly something found through searching. My only real contribution are the #define's and putting it all together. I used the test4bad g++ line below to test the code. Without the two changes above it could crash. With the two changes it worked as expected. In all cases the test4good builds always worked.

// Make with one of the following
//   g++ -O0 -g3 test4.cpp -o test4bad  -lOpenGL -lSDL
//   g++ -O0 -g3 test4.cpp -o test4good -lGL     -lSDL
//

/*
 * SDL OpenGL Tutorial.
 * (c) Michael Vance, 2000
 * briareos@lokigames.com
 *
 * Distributed under terms of the LGPL. 
 */

#include <SDL/SDL.h>
#include <GL/gl.h>

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

#define GLGETSTRING(n) ((const GLubyte * (*) (GLenum)) SDL_GL_GetProcAddress("glGetString")) (n);
#define GLCLEAR(m) ((void (*) (GLbitfield)) SDL_GL_GetProcAddress("glClear")) (m);
#define GLMATRIXMODE(m) ((void (*) (GLbitfield)) SDL_GL_GetProcAddress("glMatrixMode")) (m);
#define GLLOADIDENTITY(m) ((void (*) (void)) SDL_GL_GetProcAddress("glLoadIdentity")) ();
#define GLTRANSLATEF(x,y,z) ((void (*) (GLfloat, GLfloat, GLfloat)) SDL_GL_GetProcAddress("glTranslatef")) (x,y,z);
#define GLROTATEF(a,x,y,z) ((void (*) (GLfloat, GLfloat, GLfloat, GLfloat)) SDL_GL_GetProcAddress("glRotatef")) (a,x,y,z);
#define GLBEGIN(m) ((void (*) (GLenum)) SDL_GL_GetProcAddress("glBegin")) (m);
#define GLEND() ((void (*) (void)) SDL_GL_GetProcAddress("glEnd")) ();
#define GLCOLOR4UBV(c) ((void (*) (const GLubyte *)) SDL_GL_GetProcAddress("glColor4ubv")) (c);
#define GLVERTEX3FV(v) ((void (*) (const GLfloat *)) SDL_GL_GetProcAddress("glVertex3fv")) (v);
#define GLSHADEMODEL(m) ((void (*) (GLenum)) SDL_GL_GetProcAddress("glShadeModel")) (m);
#define GLCULLFACE(m) ((void (*) (GLenum)) SDL_GL_GetProcAddress("glCullFace")) (m);
#define GLFRONTFACE(m) ((void (*) (GLenum)) SDL_GL_GetProcAddress("glFrontFace")) (m);
#define GLENABLE(m) ((void (*) (GLenum)) SDL_GL_GetProcAddress("glEnable")) (m);
#define GLCLEARCOLOR(r,g,b,a) ((void (*) (GLclampf,GLclampf,GLclampf,GLclampf)) SDL_GL_GetProcAddress("glClearColor")) (r,g,b,a);
#define GLVIEWPORT(x,y,w,h) ((void (*) (GLint,GLint,GLsizei,GLsizei)) SDL_GL_GetProcAddress("glViewport")) (x,y,w,h);
#define GLFRUSTUM(l,r,b,t,nv,fv) ((void (*) (GLdouble,GLdouble,GLdouble,GLdouble,GLdouble,GLdouble)) SDL_GL_GetProcAddress("glFrustum")) (l,r,b,t,nv,fv);

static GLboolean should_rotate = GL_TRUE;

static void quit_tutorial( int code )
{
    /*
     * Quit SDL so we can release the fullscreen
     * mode and restore the previous video settings,
     * etc.
     */
    SDL_Quit( );

    /* Exit program. */
    exit( code );
}

static void handle_key_down( SDL_keysym* keysym )
{

    /* 
     * We're only interested if 'Esc' has
     * been presssed.
     *
     * EXERCISE: 
     * Handle the arrow keys and have that change the
     * viewing position/angle.
     */
    switch( keysym->sym ) {
    case SDLK_ESCAPE:
        quit_tutorial( 0 );
        break;
    case SDLK_SPACE:
        should_rotate = !should_rotate;
        break;
    default:
        break;
    }

}

static void process_events( void )
{
    /* Our SDL event placeholder. */
    SDL_Event event;

    /* Grab all the events off the queue. */
    while( SDL_PollEvent( &event ) ) {

        switch( event.type ) {
        case SDL_KEYDOWN:
            /* Handle key presses. */
            handle_key_down( &event.key.keysym );
            break;
        case SDL_QUIT:
            /* Handle quit requests (like Ctrl-c). */
            quit_tutorial( 0 );
            break;
        }

    }

}

static void draw_screen( void )
{
    /* Our angle of rotation. */
    static float angle = 0.0f;

    /*
     * EXERCISE:
     * Replace this awful mess with vertex
     * arrays and a call to glDrawElements.
     *
     * EXERCISE:
     * After completing the above, change
     * it to use compiled vertex arrays.
     *
     * EXERCISE:
     * Verify my windings are correct here ;).
     */
    static GLfloat v0[] = { -1.0f, -1.0f,  1.0f };
    static GLfloat v1[] = {  1.0f, -1.0f,  1.0f };
    static GLfloat v2[] = {  1.0f,  1.0f,  1.0f };
    static GLfloat v3[] = { -1.0f,  1.0f,  1.0f };
    static GLfloat v4[] = { -1.0f, -1.0f, -1.0f };
    static GLfloat v5[] = {  1.0f, -1.0f, -1.0f };
    static GLfloat v6[] = {  1.0f,  1.0f, -1.0f };
    static GLfloat v7[] = { -1.0f,  1.0f, -1.0f };
    static GLubyte red[]    = { 255,   0,   0, 255 };
    static GLubyte green[]  = {   0, 255,   0, 255 };
    static GLubyte blue[]   = {   0,   0, 255, 255 };
    static GLubyte white[]  = { 255, 255, 255, 255 };
    static GLubyte yellow[] = {   0, 255, 255, 255 };
    static GLubyte black[]  = {   0,   0,   0, 255 };
    static GLubyte orange[] = { 255, 255,   0, 255 };
    static GLubyte purple[] = { 255,   0, 255,   0 };

    /* Clear the color and depth buffers. */
    GLCLEAR( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    /* We don't want to modify the projection matrix. */
    GLMATRIXMODE( GL_MODELVIEW );
    GLLOADIDENTITY( );

    /* Move down the z-axis. */
    GLTRANSLATEF( 0.0, 0.0, -5.0 );

    /* Rotate. */
    GLROTATEF( angle, 0.0, 1.0, 0.0 );

    if( should_rotate ) {

        if( ++angle > 360.0f ) {
            angle = 0.0f;
        }

    }

    /* Send our triangle data to the pipeline. */
    GLBEGIN( GL_TRIANGLES );

    GLCOLOR4UBV( red );
    GLVERTEX3FV( v0 );
    GLCOLOR4UBV( green );
    GLVERTEX3FV( v1 );
    GLCOLOR4UBV( blue );
    GLVERTEX3FV( v2 );

    GLCOLOR4UBV( red );
    GLVERTEX3FV( v0 );
    GLCOLOR4UBV( blue );
    GLVERTEX3FV( v2 );
    GLCOLOR4UBV( white );
    GLVERTEX3FV( v3 );

    GLCOLOR4UBV( green );
    GLVERTEX3FV( v1 );
    GLCOLOR4UBV( black );
    GLVERTEX3FV( v5 );
    GLCOLOR4UBV( orange );
    GLVERTEX3FV( v6 );

    GLCOLOR4UBV( green );
    GLVERTEX3FV( v1 );
    GLCOLOR4UBV( orange );
    GLVERTEX3FV( v6 );
    GLCOLOR4UBV( blue );
    GLVERTEX3FV( v2 );

    GLCOLOR4UBV( black );
    GLVERTEX3FV( v5 );
    GLCOLOR4UBV( yellow );
    GLVERTEX3FV( v4 );
    GLCOLOR4UBV( purple );
    GLVERTEX3FV( v7 );

    GLCOLOR4UBV( black );
    GLVERTEX3FV( v5 );
    GLCOLOR4UBV( purple );
    GLVERTEX3FV( v7 );
    GLCOLOR4UBV( orange );
    GLVERTEX3FV( v6 );

    GLCOLOR4UBV( yellow );
    GLVERTEX3FV( v4 );
    GLCOLOR4UBV( red );
    GLVERTEX3FV( v0 );
    GLCOLOR4UBV( white );
    GLVERTEX3FV( v3 );

    GLCOLOR4UBV( yellow );
    GLVERTEX3FV( v4 );
    GLCOLOR4UBV( white );
    GLVERTEX3FV( v3 );
    GLCOLOR4UBV( purple );
    GLVERTEX3FV( v7 );

    GLCOLOR4UBV( white );
    GLVERTEX3FV( v3 );
    GLCOLOR4UBV( blue );
    GLVERTEX3FV( v2 );
    GLCOLOR4UBV( orange );
    GLVERTEX3FV( v6 );

    GLCOLOR4UBV( white );
    GLVERTEX3FV( v3 );
    GLCOLOR4UBV( orange );
    GLVERTEX3FV( v6 );
    GLCOLOR4UBV( purple );
    GLVERTEX3FV( v7 );

    GLCOLOR4UBV( green );
    GLVERTEX3FV( v1 );
    GLCOLOR4UBV( red );
    GLVERTEX3FV( v0 );
    GLCOLOR4UBV( yellow );
    GLVERTEX3FV( v4 );

    GLCOLOR4UBV( green );
    GLVERTEX3FV( v1 );
    GLCOLOR4UBV( yellow );
    GLVERTEX3FV( v4 );
    GLCOLOR4UBV( black );
    GLVERTEX3FV( v5 );

    GLEND( );

    /*
     * EXERCISE:
     * Draw text telling the user that 'Spc'
     * pauses the rotation and 'Esc' quits.
     * Do it using vetors and textured quads.
     */

    /*
     * Swap the buffers. This this tells the driver to
     * render the next frame from the contents of the
     * back-buffer, and to set all rendering operations
     * to occur on what was the front-buffer.
     *
     * Double buffering prevents nasty visual tearing
     * from the application drawing on areas of the
     * screen that are being updated at the same time.
     */
    SDL_GL_SwapBuffers( );
}

static void perspectiveGL( GLdouble fovY, GLdouble aspect, GLdouble zNear, GLdouble zFar )
{
    const GLdouble pi = 3.1415926535897932384626433832795;
    GLdouble fW, fH;

    //fH = tan( (fovY / 2) / 180 * pi ) * zNear;
    fH = tan( fovY / 360 * pi ) * zNear;
    fW = fH * aspect;

    GLFRUSTUM( -fW, fW, -fH, fH, zNear, zFar );
}

static void setup_opengl( int width, int height )
{
    float ratio = (float) width / (float) height;

    /* Our shading model--Gouraud (smooth). */
    GLSHADEMODEL( GL_SMOOTH );

    /* Culling. */
    GLCULLFACE( GL_BACK );
    GLFRONTFACE( GL_CCW );
    GLENABLE( GL_CULL_FACE );

    /* Set the clear color. */
    GLCLEARCOLOR( 0, 0, 0, 0 );

    /* Setup our viewport. */
    GLVIEWPORT( 0, 0, width, height );

    /*
     * Change to the projection matrix and set
     * our viewing volume.
     */
    GLMATRIXMODE( GL_PROJECTION );
    GLLOADIDENTITY( );
    /*
     * EXERCISE:
     * Replace this with a call to glFrustum.
     */
    perspectiveGL( 60.0, ratio, 1.0, 1024.0 );
}

int main( int argc, char* argv[] )
{
    /* Information about the current video settings. */
    const SDL_VideoInfo* info = NULL;
    /* Dimensions of our window. */
    int width = 0;
    int height = 0;
    /* Color depth in bits of our window. */
    int bpp = 0;
    /* Flags we will pass into SDL_SetVideoMode. */
    int flags = 0;

    /* First, initialize SDL's video subsystem. */
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
        /* Failed, exit. */
        fprintf( stderr, "Video initialization failed: %s\n",
             SDL_GetError( ) );
        quit_tutorial( 1 );
    }

    /* Let's get some video information. */
    info = SDL_GetVideoInfo( );

    if( !info ) {
        /* This should probably never happen. */
        fprintf( stderr, "Video query failed: %s\n",
             SDL_GetError( ) );
        quit_tutorial( 1 );
    }

    /*
     * Set our width/height to 640/480 (you would
     * of course let the user decide this in a normal
     * app). We get the bpp we will request from
     * the display. On X11, VidMode can't change
     * resolution, so this is probably being overly
     * safe. Under Win32, ChangeDisplaySettings
     * can change the bpp.
     */
    width = 640;
    height = 480;
    bpp = info->vfmt->BitsPerPixel;

    /*
     * Now, we want to setup our requested
     * window attributes for our OpenGL window.
     * We want *at least* 5 bits of red, green
     * and blue. We also want at least a 16-bit
     * depth buffer.
     *
     * The last thing we do is request a double
     * buffered window. '1' turns on double
     * buffering, '0' turns it off.
     *
     * Note that we do not use SDL_DOUBLEBUF in
     * the flags to SDL_SetVideoMode. That does
     * not affect the GL attribute state, only
     * the standard 2D blitting setup.
     */
    SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
    SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
    SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

    /*
     * We want to request that SDL provide us
     * with an OpenGL window, in a fullscreen
     * video mode.
     *
     * EXERCISE:
     * Make starting windowed an option, and
     * handle the resize events properly with
     * glViewport.
     */
    flags = SDL_OPENGL /*| SDL_FULLSCREEN*/;

    /*
     * Set the video mode
     */
    if( SDL_SetVideoMode( width, height, bpp, flags ) == 0 ) {
        /* 
         * This could happen for a variety of reasons,
         * including DISPLAY not being set, the specified
         * resolution not being available, etc.
         */
        fprintf( stderr, "Video mode set failed: %s\n",
             SDL_GetError( ) );
        quit_tutorial( 1 );
    }

    /*
     * At this point, we should have a properly setup
     * double-buffered window for use with OpenGL.
     */
    setup_opengl( width, height );

    /*
     * Now we want to begin our normal app process--
     * an event loop with a lot of redrawing.
     */
    while( 1 ) {
        /* Process incoming events. */
        process_events( );
        /* Draw the screen. */
        draw_screen( );
        SDL_Delay (5);

        const unsigned char * tmp = GLGETSTRING(GL_RENDERER);
        if (tmp == NULL)
        {
            printf ("CAN'T DETERMINE RENDERER\n");
        }
        else
        {
            //printf ("%s\n", tmp);
        }

    }

    /*
     * EXERCISE:
     * Record timings using SDL_GetTicks() and
     * and print out frames per second at program
     * end.
     */

    /* Never reached. */
    return 0;
}
stephengtuggy commented 2 years ago

Here is a small example of a way to proceed. The two tricks I've found are:

1. All glXxx() calls must be from a SDL_GL_GetProcAddress().  See the ugly #define's at the top of the code below.

2. glu functions must not be used.  In the example below I had to replace gluPerspective() with a function that calls glFrustum().

Nice work on this. Certainly the above is one way to solve the problem. However, I'm curious to know if my alternate solution using GLVND, works equally well.

@monohydroxy would you be able to git clone or download https://github.com/stephengtuggy/Vega-Strike-Engine-Source/tree/glvnd-on-linux? Then try building and running it, and see if it works? Note that you will need libglvnd-dev installed.

monohydroxy commented 2 years ago

Hi @stephengtuggy, Your branch didn't work for me. I think I have the opposite issue. If I take the master branch and set OpenGL to Legacy mode then it works. I put this line right after the '#Find GL' line in the CMakeLists.txt file. SET(OpenGL_GL_PREFERENCE "LEGACY")

stephengtuggy commented 2 years ago

@monohydroxy Hmm. Interesting. OK.

You should be able to change that setting from the command line, without having to modify the actual CMakeLists.txt file. Try passing -DVEGA_STRIKE_PREFER_MESA_OPENGL=ON to script/build.sh (or to cmake directly).

monohydroxy commented 2 years ago

@stephengtuggy, yes passing it on the command line works as well.

stephengtuggy commented 2 years ago

@stephengtuggy, yes passing it on the command line works as well.

@monohydroxy that's good to hear! It sounds like #557 will solve this problem, because now folks will have a command-line option for which GL implementation to use.

Well, #557 will solve it on master, anyway. We still need to figure out what to do about 0.7.x and 0.8.x.

BenjamenMeyer commented 2 years ago

@stephengtuggy at the moment I kind of lean towards porting it to 0.7.x and making a new minor release since we've been taking a while for 0.8.x and it doesn't look like there's a specific release date in sight yet (:disappointed:)

stephengtuggy commented 2 years ago

@BenjamenMeyer right now I'm not 100% sure we CAN port the fix to 0.7.x. At least not without moving to cmake 3.11 like we've done on master. We need 3.11 in order to be able to choose intelligently between different GL/GLU implementations.

Otherwise we'll have to change to using SDL_GL_GetProcAddress everywhere, which will be a big delta. And even that is not guaranteed to work for all cases. I seem to recall something about certain textures causing a crash still?

BenjamenMeyer commented 2 years ago

@stephengtuggy that's fair.

stephengtuggy commented 2 years ago

This issue probably needs to stay open until we fix it on 0.8.x, at a minimum.

stephengtuggy commented 2 years ago

592 fixes this on 0.8.x, I believe. Now all that we're waiting for is for #585 to get approved and merged to master.

stephengtuggy commented 2 years ago

585 has now been merged. So I believe this issue is fixed in both 0.8.x and 0.9.x/master. We can probably close the ticket once 0.8.x is released.

BenjamenMeyer commented 2 years ago

If the fixes are in for master and 0.8.x then we can close this so that it progresses on those boards so we know we're progressing towards release.