• Advertisement
  • Popular Tags

  • Popular Now

  • Advertisement
  • Similar Content

    • By tj8146
      I am using immediate mode for OpenGL and I am creating a 2D top down car game. I am trying to configure my game loop in order to get my car-like physics working on a square shape. I have working code but it is not doing as I want it to. I am not sure as to whether it is my game loop that is incorrect or my code for the square is incorrect, or maybe both! Could someone help because I have been trying to work this out for over a day now
      I have attached my .cpp file if you wish to run it for yourself.. 
      WinMain code:
      /******************* WIN32 FUNCTIONS ***************************/ int WINAPI WinMain( HINSTANCE hInstance, // Instance HINSTANCE hPrevInstance, // Previous Instance LPSTR lpCmdLine, // Command Line Parameters int nCmdShow) // Window Show State { MSG msg; // Windows Message Structure bool done=false; // Bool Variable To Exit Loop Car car; car.x = 220; car.y = 140; car.dx = 0; car.dy = 0; car.ang = 0; AllocConsole(); FILE *stream; freopen_s(&stream, "CONOUT$", "w", stdout); // Create Our OpenGL Window if (!CreateGLWindow("OpenGL Win32 Example",screenWidth,screenHeight)) { return 0; // Quit If Window Was Not Created } while(!done) // Loop That Runs While done=FALSE { if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // Is There A Message Waiting? { if (msg.message==WM_QUIT) // Have We Received A Quit Message? { done=true; // If So done=TRUE break; } else // If Not, Deal With Window Messages { TranslateMessage(&msg); // Translate The Message DispatchMessage(&msg); // Dispatch The Message } } else // If There Are No Messages { if(keys[VK_ESCAPE]) done = true; void processKeys(Car& car); //process keyboard while (game_is_running) { loops = 0; while (GetTickCount() > next_game_tick && loops < MAX_FRAMESKIP) { update(car); // update variables next_game_tick += SKIP_TICKS; loops++; } display(car); // Draw The Scene SwapBuffers(hDC); // Swap Buffers (Double Buffering) } } } // Shutdown KillGLWindow(); // Kill The Window return (int)(msg.wParam); // Exit The Program } //WIN32 Processes function - useful for responding to user inputs or other events. LRESULT CALLBACK WndProc( HWND hWnd, // Handle For This Window UINT uMsg, // Message For This Window WPARAM wParam, // Additional Message Information LPARAM lParam) // Additional Message Information { switch (uMsg) // Check For Windows Messages { case WM_CLOSE: // Did We Receive A Close Message? { PostQuitMessage(0); // Send A Quit Message return 0; // Jump Back } break; case WM_SIZE: // Resize The OpenGL Window { reshape(LOWORD(lParam),HIWORD(lParam)); // LoWord=Width, HiWord=Height return 0; // Jump Back } break; case WM_LBUTTONDOWN: { mouse_x = LOWORD(lParam); mouse_y = screenHeight - HIWORD(lParam); LeftPressed = true; } break; case WM_LBUTTONUP: { LeftPressed = false; } break; case WM_MOUSEMOVE: { mouse_x = LOWORD(lParam); mouse_y = screenHeight - HIWORD(lParam); } break; case WM_KEYDOWN: // Is A Key Being Held Down? { keys[wParam] = true; // If So, Mark It As TRUE return 0; // Jump Back } break; case WM_KEYUP: // Has A Key Been Released? { keys[wParam] = false; // If So, Mark It As FALSE return 0; // Jump Back } break; } // Pass All Unhandled Messages To DefWindowProc return DefWindowProc(hWnd,uMsg,wParam,lParam); }  
      C++ and OpenGL code:
      int mouse_x=0, mouse_y=0; bool LeftPressed = false; int screenWidth=1080, screenHeight=960; bool keys[256]; float radiansFromDegrees(float deg) { return deg * (M_PI / 180.0f); } float degreesFromRadians(float rad) { return rad / (M_PI / 180.0f); } bool game_is_running = true; const int TICKS_PER_SECOND = 50; const int SKIP_TICKS = 1000 / TICKS_PER_SECOND; const int MAX_FRAMESKIP = 10; DWORD next_game_tick = GetTickCount(); int loops; typedef struct { float x, y; float dx, dy; float ang; }Car; //OPENGL FUNCTION PROTOTYPES void display(const Car& car); //called in winmain to draw everything to the screen void reshape(int width, int height); //called when the window is resized void init(); //called in winmain when the program starts. void processKeys(Car& car); //called in winmain to process keyboard input void update(Car& car); //called in winmain to update variables /************* START OF OPENGL FUNCTIONS ****************/ void display(const Car& car) { const float w = 50.0f; const float h = 50.0f; glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glTranslatef(100, 100, 0); glBegin(GL_POLYGON); glVertex2f(car.x, car.y); glVertex2f(car.x + w, car.y); glVertex2f(car.x + w, car.y + h); glVertex2f(car.x, car.y + h); glEnd(); glFlush(); } void reshape(int width, int height) // Resize the OpenGL window { screenWidth = width; screenHeight = height; // to ensure the mouse coordinates match // we will use these values to set the coordinate system glViewport(0, 0, width, height); // Reset the current viewport glMatrixMode(GL_PROJECTION); // select the projection matrix stack glLoadIdentity(); // reset the top of the projection matrix to an identity matrix gluOrtho2D(0, screenWidth, 0, screenHeight); // set the coordinate system for the window glMatrixMode(GL_MODELVIEW); // Select the modelview matrix stack glLoadIdentity(); // Reset the top of the modelview matrix to an identity matrix } void init() { glClearColor(1.0, 1.0, 0.0, 0.0); //sets the clear colour to yellow //glClear(GL_COLOR_BUFFER_BIT) in the display function //will clear the buffer to this colour. } void processKeys(Car& car) { if (keys[VK_UP]) { float cdx = sinf(radiansFromDegrees(car.ang)); float cdy = -cosf(radiansFromDegrees(car.ang)); car.dx += cdx; car.dy += cdy; } if (keys[VK_DOWN]) { float cdx = sinf(radiansFromDegrees(car.ang)); float cdy = -cosf(radiansFromDegrees(car.ang)); car.dx += -cdx; car.dy += -cdy; } if (keys[VK_LEFT]) { car.ang -= 2; } if (keys[VK_RIGHT]) { car.ang += 2; } } void update(Car& car) { car.x += car.dx*next_game_tick; }  
      game.cpp
    • By tj8146
      I am using immediate mode for OpenGL and I am creating a 2D top down car game. I am trying to configure my game loop in order to get my car-like physics working on a square shape. I have working code but it is not doing as I want it to. I am not sure as to whether it is my game loop that is incorrect or my code for the square is incorrect, or maybe both! Could someone help because I have been trying to work this out for over a day now
      I have attached my .cpp file if you wish to run it for yourself.. 
       
      This is my C++ and OpenGL code:
      int mouse_x=0, mouse_y=0; bool LeftPressed = false; int screenWidth=1080, screenHeight=960; bool keys[256]; float radiansFromDegrees(float deg) { return deg * (M_PI / 180.0f); } float degreesFromRadians(float rad) { return rad / (M_PI / 180.0f); } bool game_is_running = true; const int TICKS_PER_SECOND = 50; const int SKIP_TICKS = 1000 / TICKS_PER_SECOND; const int MAX_FRAMESKIP = 10; DWORD next_game_tick = GetTickCount(); int loops; typedef struct { float x, y; float dx, dy; float ang; }Car; //OPENGL FUNCTION PROTOTYPES void display(const Car& car); //called in winmain to draw everything to the screen void reshape(int width, int height); //called when the window is resized void init(); //called in winmain when the program starts. void processKeys(Car& car); //called in winmain to process keyboard input void update(Car& car); //called in winmain to update variables /************* START OF OPENGL FUNCTIONS ****************/ void display(const Car& car) { const float w = 50.0f; const float h = 50.0f; glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glTranslatef(100, 100, 0); glBegin(GL_POLYGON); glVertex2f(car.x, car.y); glVertex2f(car.x + w, car.y); glVertex2f(car.x + w, car.y + h); glVertex2f(car.x, car.y + h); glEnd(); glFlush(); } void reshape(int width, int height) // Resize the OpenGL window { screenWidth = width; screenHeight = height; // to ensure the mouse coordinates match // we will use these values to set the coordinate system glViewport(0, 0, width, height); // Reset the current viewport glMatrixMode(GL_PROJECTION); // select the projection matrix stack glLoadIdentity(); // reset the top of the projection matrix to an identity matrix gluOrtho2D(0, screenWidth, 0, screenHeight); // set the coordinate system for the window glMatrixMode(GL_MODELVIEW); // Select the modelview matrix stack glLoadIdentity(); // Reset the top of the modelview matrix to an identity matrix } void init() { glClearColor(1.0, 1.0, 0.0, 0.0); //sets the clear colour to yellow //glClear(GL_COLOR_BUFFER_BIT) in the display function //will clear the buffer to this colour. } void processKeys(Car& car) { if (keys[VK_UP]) { float cdx = sinf(radiansFromDegrees(car.ang)); float cdy = -cosf(radiansFromDegrees(car.ang)); car.dx += cdx; car.dy += cdy; } if (keys[VK_DOWN]) { float cdx = sinf(radiansFromDegrees(car.ang)); float cdy = -cosf(radiansFromDegrees(car.ang)); car.dx += -cdx; car.dy += -cdy; } if (keys[VK_LEFT]) { car.ang -= 2; } if (keys[VK_RIGHT]) { car.ang += 2; } } void update(Car& car) { car.x += car.dx*next_game_tick; } My WinMain code:
      /******************* WIN32 FUNCTIONS ***************************/ int WINAPI WinMain( HINSTANCE hInstance, // Instance HINSTANCE hPrevInstance, // Previous Instance LPSTR lpCmdLine, // Command Line Parameters int nCmdShow) // Window Show State { MSG msg; // Windows Message Structure bool done=false; // Bool Variable To Exit Loop Car car; car.x = 220; car.y = 140; car.dx = 0; car.dy = 0; car.ang = 0; AllocConsole(); FILE *stream; freopen_s(&stream, "CONOUT$", "w", stdout); // Create Our OpenGL Window if (!CreateGLWindow("OpenGL Win32 Example",screenWidth,screenHeight)) { return 0; // Quit If Window Was Not Created } while(!done) // Loop That Runs While done=FALSE { if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // Is There A Message Waiting? { if (msg.message==WM_QUIT) // Have We Received A Quit Message? { done=true; // If So done=TRUE break; } else // If Not, Deal With Window Messages { TranslateMessage(&msg); // Translate The Message DispatchMessage(&msg); // Dispatch The Message } } else // If There Are No Messages { if(keys[VK_ESCAPE]) done = true; void processKeys(Car& car); //process keyboard while (game_is_running) { loops = 0; while (GetTickCount() > next_game_tick && loops < MAX_FRAMESKIP) { update(car); // update variables next_game_tick += SKIP_TICKS; loops++; } display(car); // Draw The Scene SwapBuffers(hDC); // Swap Buffers (Double Buffering) } } } // Shutdown KillGLWindow(); // Kill The Window return (int)(msg.wParam); // Exit The Program } //WIN32 Processes function - useful for responding to user inputs or other events. LRESULT CALLBACK WndProc( HWND hWnd, // Handle For This Window UINT uMsg, // Message For This Window WPARAM wParam, // Additional Message Information LPARAM lParam) // Additional Message Information { switch (uMsg) // Check For Windows Messages { case WM_CLOSE: // Did We Receive A Close Message? { PostQuitMessage(0); // Send A Quit Message return 0; // Jump Back } break; case WM_SIZE: // Resize The OpenGL Window { reshape(LOWORD(lParam),HIWORD(lParam)); // LoWord=Width, HiWord=Height return 0; // Jump Back } break; case WM_LBUTTONDOWN: { mouse_x = LOWORD(lParam); mouse_y = screenHeight - HIWORD(lParam); LeftPressed = true; } break; case WM_LBUTTONUP: { LeftPressed = false; } break; case WM_MOUSEMOVE: { mouse_x = LOWORD(lParam); mouse_y = screenHeight - HIWORD(lParam); } break; case WM_KEYDOWN: // Is A Key Being Held Down? { keys[wParam] = true; // If So, Mark It As TRUE return 0; // Jump Back } break; case WM_KEYUP: // Has A Key Been Released? { keys[wParam] = false; // If So, Mark It As FALSE return 0; // Jump Back } break; } // Pass All Unhandled Messages To DefWindowProc return DefWindowProc(hWnd,uMsg,wParam,lParam); }  
      game.cpp
    • By lxjk
      Hi guys,
      There are many ways to do light culling in tile-based shading. I've been playing with this idea for a while, and just want to throw it out there.
      Because tile frustums are general small compared to light radius, I tried using cone test to reduce false positives introduced by commonly used sphere-frustum test.
      On top of that, I use distance to camera rather than depth for near/far test (aka. sliced by spheres).
      This method can be naturally extended to clustered light culling as well.
      The following image shows the general ideas

       
      Performance-wise I get around 15% improvement over sphere-frustum test. You can also see how a single light performs as the following: from left to right (1) standard rendering of a point light; then tiles passed the test of (2) sphere-frustum test; (3) cone test; (4) spherical-sliced cone test
       

       
      I put the details in my blog post (https://lxjk.github.io/2018/03/25/Improve-Tile-based-Light-Culling-with-Spherical-sliced-Cone.html), GLSL source code included!
       
      Eric
    • By Fadey Duh
      Good evening everyone!

      I was wondering if there is something equivalent of  GL_NV_blend_equation_advanced for AMD?
      Basically I'm trying to find more compatible version of it.

      Thank you!
    • By Jens Eckervogt
      Hello guys, 
       
      Please tell me! 
      How do I know? Why does wavefront not show for me?
      I already checked I have non errors yet.
      using OpenTK; using System.Collections.Generic; using System.IO; using System.Text; namespace Tutorial_08.net.sourceskyboxer { public class WaveFrontLoader { private static List<Vector3> inPositions; private static List<Vector2> inTexcoords; private static List<Vector3> inNormals; private static List<float> positions; private static List<float> texcoords; private static List<int> indices; public static RawModel LoadObjModel(string filename, Loader loader) { inPositions = new List<Vector3>(); inTexcoords = new List<Vector2>(); inNormals = new List<Vector3>(); positions = new List<float>(); texcoords = new List<float>(); indices = new List<int>(); int nextIdx = 0; using (var reader = new StreamReader(File.Open("Contents/" + filename + ".obj", FileMode.Open), Encoding.UTF8)) { string line = reader.ReadLine(); int i = reader.Read(); while (true) { string[] currentLine = line.Split(); if (currentLine[0] == "v") { Vector3 pos = new Vector3(float.Parse(currentLine[1]), float.Parse(currentLine[2]), float.Parse(currentLine[3])); inPositions.Add(pos); if (currentLine[1] == "t") { Vector2 tex = new Vector2(float.Parse(currentLine[1]), float.Parse(currentLine[2])); inTexcoords.Add(tex); } if (currentLine[1] == "n") { Vector3 nom = new Vector3(float.Parse(currentLine[1]), float.Parse(currentLine[2]), float.Parse(currentLine[3])); inNormals.Add(nom); } } if (currentLine[0] == "f") { Vector3 pos = inPositions[0]; positions.Add(pos.X); positions.Add(pos.Y); positions.Add(pos.Z); Vector2 tc = inTexcoords[0]; texcoords.Add(tc.X); texcoords.Add(tc.Y); indices.Add(nextIdx); ++nextIdx; } reader.Close(); return loader.loadToVAO(positions.ToArray(), texcoords.ToArray(), indices.ToArray()); } } } } } And It have tried other method but it can't show for me.  I am mad now. Because any OpenTK developers won't help me.
      Please help me how do I fix.

      And my download (mega.nz) should it is original but I tried no success...
      - Add blend source and png file here I have tried tried,.....  
       
      PS: Why is our community not active? I wait very longer. Stop to lie me!
      Thanks !
  • Advertisement
  • Advertisement
Sign in to follow this  

OpenGL Efficient resource manager for OpenGL in C++?

This topic is 756 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm writing a very small engine to learn more about modern OpenGL, and i'm looking for some examples and learning material on how to write an efficient resource manager for assets like textures, models, sounds, etc. Does anyone recommend anything? Books, tutorials, samples, libraries, anything. :)

Edited by vinnyvicious

Share this post


Link to post
Share on other sites
Advertisement

Efficient for the computer or for you? What a about put files in folders and load everything on startup into RAM? When (If) you ever hit 1 GB your objectOrientenDependencyInjectedEntityMappedCode is surely flexible enough to get a streaming treatment.

Share this post


Link to post
Share on other sites

I just store them in a vector, and pass the array index around inside an opaque handle ¯\_(?)_/¯ Also keep a map around for string to index lookups. Right now indexes are never reused, makes it easier to track use-after-delete.

 

Of course things get rather a lot more complex with streaming.

Edited by Promit

Share this post


Link to post
Share on other sites

I recently designed a resource management system. I liked the straight-forwardness of DOOM WAD files, so I copied this style and made my own solution. Maybe you'll like the idea too:

  • Store all assets within a single archive file (does not need to be encrypted)
  • Beginning of file is a table that maps file names to offsets in the archive
  • Each file-entry is just the raw file placed straight into the archive, can do compression, but I didn't

The nice thing about this style is when the time comes to package the game up for release there's only one asset file. It can be a little weird if the file gets over 2GB in size since your file i/o API will need to be able to handle 64-bit integers for file sizes. If disk-seek optimization is ever needed (or if you want to do seek optimization for fun) the ordering in the archive can be modified. When the game launches the archive can opened and the map-table can be read into game memory -- this can act like a "symbol table" of all the files that the game can request. The symbols are stored in a hash table, where the key is the file-path and the value is information about that asset + a handle to the asset (if it's been loaded into memory).

 

To let artists keep modifying files at-will all the asset files are kept in our repository and there's a function that can be called to package up all the assets into a new archive. File name + paths are used as keys into the archive, and placed in that initial lookup-table I described earlier. This way the asset archive doesn't really affect the workflow of the artists. We used some recursive directory-crawling code to do this.

 

Anyway, hope that helps!

Share this post


Link to post
Share on other sites

Yeah why you need a manager for something which is plain data? When I read code from others, "Manager" typically marks the classes which have to be replaced by a sane design pattern.

Share this post


Link to post
Share on other sites
Since you said "small", my approach might just work for you.

I'm simply memory mapping a large binary file which is "compiled" with a custom tool. When I say "compiled", it basically means reading a structured "definition file" that tells the compiler who references whom and what the asset names and file names are. It calculates a hash of every name prepended with a salt and then checks that all hashes are unique. Then it calculates offsets by adding up sizes, and pukes everything (array of structures, followed by binary contents of every file) into one big, ugly, blob. Some people sneer at storing a structure as-is, and they are kind of right, but with asset compiler and game built with the same compiler and running on the same architecture, it's a bit of a "so what" situation.

For the few assets that you actually want to look up by name later (in fact, other than "load screen", and "menu", and "level 1", you shouldn't need all that many), you must know the salt, and unluckily, you must do the hash at runtime, so the salt needs to be stored in the file header. For the overwhelming majority of assets (which are referenced by other assets within the asset file) you don't really care about their name (it would of course be possible to load them with a string name, but why... if level 1 uses assets #123 and #456, that's really all you need to know). Each asset that references another one does that by its hash. The asset compiler makes sure, at build time, that all the hashes are all consistent. It would arguably be "better" do do it with strings (more explicit, anyway), but I'm pretty happy with this "mostly string free" approach.

Note that if you plan to frequently add assets, my "mostly string free" approach is not truly the best strategy (you could even say "catastrophic"). During development, unless your assets are terabyte-scale, the rebuild is only mildly annoying. It's more an issue if you intend to do a lot of changes regularly after shipping (say, you want to add some downloadable contents every week). In that case, you probably want a more complicated approach anyway, though. You most probably want to consider moving the "table of contents" into a separate file, or alternatively at the end of the datafile, with an offset to the start of the TOC in the file header (otherwise, adding assets is a nightmare either way because you must move stuff around).

Now, regardless of how you identify assets, by string or by hash, (that's actually pretty inconsequential!) when the game starts, you memory map that entire ugly pig of a file. As long as your assets alltogether aren't around a gigabyte or so, this is no problem (you said "small", right?) even on 32 bit. On 64 bit it's no issue anyway.

The actual "asset manager" consists basically of finding the resource's hash value (I don't even bother with something overly intelligent, simple linear search -- works better than you think, at 16 bytes per entry it's not a terribly large amount of memory you need to walk over) and then adding the offset to the mapped file's pointer. That's it, the operating system does the rest, and it does it pretty good.
Allocate? Do nothing. Free? Do nothing. Manage? Do nothing. Just dereference the pointer when you feel like doing it.

If you want to be extra zealous, pre-fault pages that you intend to access with a worker thread, that way you gain a little speed (but not much, readahead works surprisingly well). The main reason to do the faulting in a dedicated thread would be in order not to block the render thread and have hiccups, if you also load assets while the game is already running (as opposed to "at start" or "at level load"). If you do something more elaborate (like multithreaded loading, maybe with decompression) that isn't an issue anyway, the worker threads will do the faulting without you even knowing. Render thread consumes what the decompress thread produced whenever the condvar says "done".

I wouldn't ever want to use anything but memory mapping again. As long as you don't run into address space trouble under 32 bits, it reduces a pretty complex problem to "yeah, you know, just don't worry". With either workers in place doing decompression and stuff, or a dedicated prefaulter thread, it runs really really nicely, fast, and apart from the single syscall for mapping, it is 100% portable and system-agnostic.

Windows overlapped I/O traditionally used to be the often recommended "go to solution", but apart from being totally un-portable, the code is also way more complex, and at least on any system that I've seen, it's substantially slower than memory mapping, too. AIO doesn't work nearly as well under Linux either (you could even say "terribly").
Plus, with pretty much every AIO/overlapped approach you are completely tossing the filesystem cache over board, which is an immensely bad thing to do. It means you basically need to rebuild a sort of caching mechanism in your application although one that works perfectly well already exists in the operating system. Yes, you might be able to squeeze out 0.5% more performance. Maybe. Or maybe not. You might do a lot of redundant work in order to run 50% slower in the end, too.

If you want to compress assets on disk, it gets quite a bit more complicated. In that case, you must allocate and actually manage memory because you need some place where you can store the decompressed data. Enter handles or refcounted pointers.
I personally don't think nowadays compression is really that much worthwhile any more (but your mileage may certainly differ). You still gain a little if you use the correct algorithm (think e.g. LZ4, which is basically as expensive as two memcpy calls) but some are the same speed or slower than a modern harddisk, and considerably slower than a SSD. For example, zlib is just about half the speed of what the SSD delivers on my computer, and lzma is considerably slower than what even a traditional harddisk would do in bulk transfer.
So, for "small" (i.e. not something that will need a bluray), I think skipping compression alltogether may be an entirely feasible option. Just... memory map, and use the pointer.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement