Custom User Events

Passing Complex Data in Custom SDL Events

What's the most efficient way to pass complex data structures through custom events?

Abstract art representing computer programming

Passing complex data structures through custom SDL events requires careful consideration of memory management and performance. Here are some efficient approaches:

1. Using Pointers to Heap-Allocated Objects

For complex data structures, you can allocate the object on the heap and pass a pointer through the event:

#include "UserEvents.h"
#include <SDL.h>
#include <memory>

struct ComplexData {
  int id;
  std::string name;
  std::vector<float> values;
};

void PushComplexEvent() {
  SDL_Event event;
  event.type = UserEvents::COMPLEX_EVENT;

  auto data = std::make_unique<ComplexData>();
  data->id = 1;
  data->name = "Example";
  data->values = {1.0f, 2.0f, 3.0f};

  // Transfer ownership to the event
  event.user.data1 = data.release();

  SDL_PushEvent(&event);
}

void HandleComplexEvent(
    const SDL_Event& event) {
  if (event.type == UserEvents::COMPLEX_EVENT) {
    std::unique_ptr<ComplexData> data(
        static_cast<ComplexData*>(
          event.user.data1));

    // Use the data
    std::cout << "ID: " << data->id
        << ", Name: " << data->name
        << "\n";

    // The unique_ptr will automatically delete
    // the data when it goes out of scope
  }
}

int main() {
  SDL_Init(SDL_INIT_EVENTS);
  SDL_Event event;
  bool quit{false};

  PushComplexEvent();

  while (!quit) {
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT) {
        quit = true;
      } else if (event.type ==
                 UserEvents::COMPLEX_EVENT) {
        HandleComplexEvent(event);
      }
    }
  }

  SDL_Quit();
  return 0;
}

This method is efficient for large or variable-sized data structures, but requires careful memory management.

2. Using a Fixed-Size Struct

For smaller, fixed-size data structures, you can use a union within the SDL_UserEvent:

#include "UserEvents.h"
#include <SDL.h>

struct FixedSizeData {
  int id;
  float x, y, z;
  char name[32];
};

union EventData {
  FixedSizeData fixedData;
  void* ptrData;
};

void PushFixedSizeEvent() {
  SDL_Event event;
  event.type = UserEvents::FIXED_SIZE_EVENT;

  EventData data;
  data.fixedData.id = 1;
  data.fixedData.x = 1.0f;
  data.fixedData.y = 2.0f;
  data.fixedData.z = 3.0f;
  strncpy(data.fixedData.name, "Example",
          sizeof(data.fixedData.name) - 1);

  event.user.data1 =
      reinterpret_cast<void*>(data.ptrData);

  SDL_PushEvent(&event);
}

void HandleFixedSizeEvent(
    const SDL_Event& event) {
  if (event.type ==
      UserEvents::FIXED_SIZE_EVENT) {
    EventData data;
    data.ptrData = event.user.data1;

    // Use the data
    std::cout << "ID: " << data.fixedData.id
        << ", Name: "
        << data.fixedData.name << "\n";
  }
}

int main() {
  SDL_Init(SDL_INIT_EVENTS);
  SDL_Event event;
  bool quit{false};

  PushFixedSizeEvent();

  while (!quit) {
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT) {
        quit = true;
      } else if (event.type ==
                 UserEvents::FIXED_SIZE_EVENT) {
        HandleFixedSizeEvent(event);
      }
    }
  }

  SDL_Quit();
  return 0;
}

This method is very efficient and doesn't require dynamic memory allocation, but is limited to fixed-size structures that fit within the size of a pointer.

3. Using a Shared Data Store

For frequently updated data or when you need to avoid copying large amounts of data, you can use a shared data store:

#include "UserEvents.h"
#include <SDL.h>
#include <mutex>
#include <unordered_map>

struct SharedData {
  int id;
  std::string name;
  std::vector<float> values;
};

class SharedDataStore {
private:
  std::unordered_map<int, SharedData> dataMap;
  std::mutex mutex;

public:
  void UpdateData(int key,
                  const SharedData& data) {
    std::lock_guard<std::mutex> lock(mutex);
    dataMap[key] = data;
  }

  SharedData GetData(int key) {
    std::lock_guard<std::mutex> lock(mutex);
    return dataMap[key];
  }
};

SharedDataStore gDataStore;

void PushSharedDataEvent(int dataKey) {
  SDL_Event event;
  event.type = UserEvents::SHARED_DATA_EVENT;
  event.user.code = dataKey;
  SDL_PushEvent(&event);
}

void HandleSharedDataEvent(
    const SDL_Event& event) {
  if (event.type ==
      UserEvents::SHARED_DATA_EVENT) {
    int dataKey = event.user.code;
    SharedData data =
        gDataStore.GetData(dataKey);

    // Use the data
    std::cout << "ID: " << data.id
        << ", Name: " << data.name
        << "\n";
  }
}

int main() {
  SDL_Init(SDL_INIT_EVENTS);
  SDL_Event event;
  bool quit{false};

  // Update shared data
  gDataStore.UpdateData(
      1, {1, "Example", {1.0f, 2.0f, 3.0f}});
  PushSharedDataEvent(1);

  while (!quit) {
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT) {
        quit = true;
      } else if (event.type ==
                 UserEvents::
                 SHARED_DATA_EVENT) {
        HandleSharedDataEvent(event);
      }
    }
  }

  SDL_Quit();
  return 0;
}

This method is efficient for frequently updated data or very large data structures, as it avoids copying data into the event. However, it requires careful synchronization if accessed from multiple threads.

Each of these methods has its own trade-offs in terms of efficiency, flexibility, and complexity. Choose the one that best fits your specific use case and performance requirements.

This Question is from the Lesson:

Custom User Events

Discover how to use the SDL2 event system to handle custom, game-specific interactions

Answers to questions are automatically generated and may not have been reviewed.

This Question is from the Lesson:

Custom User Events

Discover how to use the SDL2 event system to handle custom, game-specific interactions

sdl2-promo.jpg
Part of the course:

Game Dev with SDL2

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

Free, unlimited access

This course includes:

  • 51 Lessons
  • 100+ Code Samples
  • 91% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved