Recent Posts

Pages: 1 2 3 4 5 6 7 8 9 10
1
Works in Progress / Retro Pacman game for Opensuse users
« Last post by hpg678 on January 10, 2023, 10:42:12 am »
Completed a retro Pacman game with a modern spin for OpenSuse users of Tumbleweed and Leap. Completely sourced and compiled to run natively. You may need to install additional dependencies which will be explained in a Readme file.
2
General ENIGMA / OpenAL Audio and FreeType Font Rendering Extension Windows Deps
« Last post by time-killer-games on July 30, 2022, 12:46:08 pm »
If you happen to want/need OpenAL or FreeType for anything, here's a zip with the required DLL's. Note some of the dependencies of both are licensed under LGPL meaning you cannot statically link with them and release your game closed source, even with a linking exception (while I know this for certain with OpenAL, I'd have to double check with FreeType). Both have missing required static libraries from the MSYS2 pacman packages anyway, so you couldn't easily do it even if you wanted to release your game open source.

TL;DR to use OpenAL/FreeType distribute these DLL's with your game:
https://drive.google.com/file/d/1gagR9bycmIQKRCKQyhMpTvwEk5mXezcE/view?usp=sharing

The "win32" folder for 32-bit games. The "win64" is for 64-bit games.

I will try to update the above link to make sure the DLL's remain up-to-date with the latest versions available intermittently. If they stop working after packages have been updated I recommend letting me know in this topic so I can update the download to have the latest versions.

I won't be updating the DLL's at all until pacman's shipped versions of gRPC/abseil/protobuff are no longer breaking the Windows build.

In the meantime you can use older versions of the Windows installer which actually work.

Technically not sure if you even need libffi but I included it in the download anyway just in case. I added that in case any of the requred DLL's use that to call other dependency functions.

Samuel
3
Function Peer Review / more code ripe for the picking
« Last post by time-killer-games on June 21, 2022, 12:57:11 am »
Code: [Select]
#if defined(_WIN32)
#include <Shlobj.h>
#elif defined(__APPLE__) && defined(__MACH__)
#include <sysdir.h>
#elif defined(__linux__)
#include <unistd.h>
#endif

namespace enigma_user {

  namespace {

    std::string directory_get_special_path(int dtype) {
      std::string result;
      #if defined(_WIN32)
      wchar_t *ptr = nullptr;
      KNOWNFOLDERID fid;
      switch (dtype) {
        case  0: { fid = FOLDERID_Desktop;   break; }
        case  1: { fid = FOLDERID_Documents; break; }
        case  2: { fid = FOLDERID_Downloads; break; }
        case  3: { fid = FOLDERID_Music;     break; }
        case  4: { fid = FOLDERID_Pictures;  break; }
        case  5: { fid = FOLDERID_Videos;    break; }
        default: { fid = FOLDERID_Desktop;   break; }
      }
      if (SUCCEEDED(SHGetKnownFolderPath(fid, KF_FLAG_CREATE | KF_FLAG_DONT_UNEXPAND, nullptr, &ptr))) {
        result = shorten(ptr);
        if (!result.empty() && result.back() != '\\') {
          result.push_back('\\');
        }
      }
      CoTaskMemFree(ptr);
      #elif defined(__APPLE__) && defined(__MACH__)
      char buf[PATH_MAX];
      sysdir_search_path_directory_t fid;
      sysdir_search_path_enumeration_state state;
      switch (dtype) {
        case  0: { fid = SYSDIR_DIRECTORY_DESKTOP;   break; }
        case  1: { fid = SYSDIR_DIRECTORY_DOCUMENT;  break; }
        case  2: { fid = SYSDIR_DIRECTORY_DOWNLOADS; break; }
        case  3: { fid = SYSDIR_DIRECTORY_MUSIC;     break; }
        case  4: { fid = SYSDIR_DIRECTORY_PICTURES;  break; }
        case  5: { fid = SYSDIR_DIRECTORY_MOVIES;    break; }
        default: { fid = SYSDIR_DIRECTORY_DESKTOP;   break; }
      }
      state = sysdir_start_search_path_enumeration(fid, SYSDIR_DOMAIN_MASK_USER);
      while ((state = sysdir_get_next_search_path_enumeration(state, buf))) {
        if (buf[0] == '~') {
          result = buf;
          result.replace(0, 1, environment_get_variable("HOME"));
          if (!result.empty() && result.back() != '/') {
            result.push_back('/');
          }
          break;
        }
      }
      #else
      std::string fid;
      switch (dtype) {
        case  0: { fid = "XDG_DESKTOP_DIR=";   break; }
        case  1: { fid = "XDG_DOCUMENTS_DIR="; break; }
        case  2: { fid = "XDG_DOWNLOAD_DIR=";  break; }
        case  3: { fid = "XDG_MUSIC_DIR=";     break; }
        case  4: { fid = "XDG_PICTURES_DIR=";  break; }
        case  5: { fid = "XDG_VIDEOS_DIR=";    break; }
        default: { fid = "XDG_DESKTOP_DIR=";   break; }
      }
      std::string conf = environment_get_variable("HOME") + "/.config/user-dirs.dirs";
      if (file_exists(conf)) {
        int dirs = file_text_open_read(conf);
        if (dirs != -1) {
          while (!file_text_eof(dirs)) {
            std::string line = file_text_read_string(dirs);
            file_text_readln(dirs);
            std::size_t pos = line.find(fid, 0);
            if (pos != std::string::npos) {
              FILE *fp = popen(("echo " + line.substr(pos + fid.length())).c_str(), "r");
              if (fp) {
                char buf[PATH_MAX];
                if (fgets(buf, PATH_MAX, fp)) {
                  std::string str = buf;
                  std::size_t pos = str.find("\n", strlen(buf) - 1);
                  if (pos != std::string::npos) {
                    str.replace(pos, 1, "");
                  }
                  if (!directory_exists(str)) {
                    directory_create(str);
                  }
                  result = str;
                  if (!result.empty() && result.back() != '/') {
                    result.push_back('/');
                  }
                }
                pclose(fp);
              }
            }
          }
          file_text_close(dirs);
        }
      }
      #endif
      return result;
    }

  } // anonymous namespace

  std::string directory_get_desktop_path() {
    return directory_get_special_path(0);
  }

  string directory_get_documents_path() {
    return directory_get_special_path(1);
  }

  std::string directory_get_downloads_path() {
    return directory_get_special_path(2);
  }

  std::string directory_get_music_path() {
    return directory_get_special_path(3);
  }

  std::string directory_get_pictures_path() {
    return directory_get_special_path(4);
  }

  std::string directory_get_videos_path() {
    return directory_get_special_path(5);
  }

} // namespace enigma_user

I am using popen()/fgets()/pclose() for expanding environment variables which is a requirement for correctly parsing the user-dirs.dirs config file:

Code: [Select]
freebsd@freebsd:~ $ cat ~/.config/user-dirs.dirs
# This file is written by xdg-user-dirs-update
# If you want to change or add directories, just edit the line you're
# interested in. All local changes will be retained on the next run.
# Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped
# homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an
# absolute path. No other format is supported.
#
XDG_DESKTOP_DIR="$HOME/Desktop"
XDG_DOWNLOAD_DIR="$HOME/Downloads"
XDG_TEMPLATES_DIR="$HOME/Templates"
XDG_PUBLICSHARE_DIR="$HOME/Public"
XDG_DOCUMENTS_DIR="$HOME/Documents"
XDG_MUSIC_DIR="$HOME/Music"
XDG_PICTURES_DIR="$HOME/Pictures"
XDG_VIDEOS_DIR="$HOME/Videos"

It's important to note these paths will not always be English due to the user-chosen system locale. This goes for all supported platforms. The path may have more than one environment variable as well as escaped quotes within the initial quoted paths on Linux and similar platforms. I don't provide a function for Templates because that is not available on macOS and on Windows it isn't in the home folder (%USERPROFILE% is basically the Windows-equivalent of $HOME on the other platforms) like it is on Linux. I don't have a function for Public because it isn't always in the home folder depending on the platform, thus aren't platform equivalents.

An important note from the Windows implementation which uses SHGetKnownFolderPath():

Quote
When this method returns, contains the address of a pointer to a null-terminated Unicode string that specifies the path of the known folder. The calling process is responsible for freeing this resource once it is no longer needed by calling CoTaskMemFree, whether SHGetKnownFolderPath succeeds or not.

...which is why i am calling CoTaskMemFree() regardless of whether the call to SHGetKnownFolderPath() succeeds or not.

Documentation citation: https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath

The paths returned on all platforms will contain a trailing slash at the end of the string. The paths will be created if they do not already exist on Windows or Linux. Mac is guaranteed to have the paths exist already, as they can't be deleted.
4
Function Peer Review / Embed Windows
« Last post by time-killer-games on May 24, 2022, 06:56:06 am »
I wrote a function for Windows and Xlib platforms which works in ENIGMA. It should also work with SDL minus Mac and Android.

You can use execute_shell() or execute_program() to have a launcher executable launch a game executable. The launcher could serve as a "choose a game" menu or even an updater application.

You can save window_identifier() since it is already a string and make it an environment variable which gets passed down to the child. The child can then plug in the environment variable it inherited as the parentWindowId and its own window_identifier() can be the child windowId parameter passed to these two functions:

Code: [Select]
// embed window identifier into parent window identifier (called once)
void WindowIdSetParentWindowId(wid_t windowId, wid_t parentWindowId) {
  #if defined(_WIN32)
  HWND child  = (HWND)(void *)(uintptr_t)strtoull(windowId.c_str(), nullptr, 10);
  HWND parent = (HWND)(void *)(uintptr_t)strtoull(parentWindowId.c_str(), nullptr, 10);
  RECT wrect; GetWindowRect(parent, &wrect); RECT crect; GetClientRect(parent, &crect);
  POINT lefttop     = { crect.left,  crect.top    }; ClientToScreen(parent, &lefttop);
  POINT bottomright = { crect.right, crect.bottom }; ClientToScreen(parent, &bottomright);
  MoveWindow(child, -(lefttop.x - wrect.left), -(lefttop.y - wrect.top), crect.right + bottomright.x, crect.bottom + bottomright.y, true);
  SetWindowLongPtr(child, GWL_STYLE, GetWindowLongPtr(child, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU | WS_POPUP | WS_SIZEBOX) | WS_CHILD);
  SetWindowLongPtr(child, GWL_EXSTYLE, GetWindowLongPtr(child, GWL_EXSTYLE) | WS_EX_TOOLWINDOW);
  SetWindowLongPtr(parent, GWL_STYLE, GetWindowLongPtr(parent, GWL_STYLE) | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
  SetParent(child, parent); ShowWindow(child, SW_MAXIMIZE);
  #elif (defined(__linux__) && !defined(__ANDROID__)) || (defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__))
  Window child  = (Window)(uintptr_t)strtoull(windowId.c_str(), nullptr, 10);
  Window parent = (Window)(uintptr_t)strtoull(parentWindowId.c_str(), nullptr, 10);
  Display *display = XOpenDisplay(nullptr); XMapWindow(display, child);
  Window root = 0, rparent = 0, *children = nullptr; unsigned int nchildren = 0;
  XQueryTree(display, child, &root, &rparent, &children, &nchildren);
  XReparentWindow(display, child, parent, 0, 0); if (nchildren > 0) { XFree(children); }
  XFlush(display); std::this_thread::sleep_for(std::chrono::milliseconds(5));
  while (parent != rparent) {
    XSynchronize(display, true);
    XQueryTree(display, child, &root, &rparent, &children, &nchildren);
    XReparentWindow(display, child, parent, 0, 0); if (nchildren > 0) { XFree(children); }
    XFlush(display); std::this_thread::sleep_for(std::chrono::milliseconds(5));
  }
  XCloseDisplay(display);
  #else
  DEBUG_MESSAGE("Unsupported platform for function!", MESSAGE_TYPE::M_INFO);
  #endif
}

// update embed area of window identifier to fill parent window identifier client area
// (must be called every step once a window is embedded inside another to function)
void WindowIdFillParentWindowId(wid_t windowId, wid_t parentWindowId) {
  if (strtoull(parentWindowId.c_str(), nullptr, 10) == 0) return;
  #if defined(_WIN32)
  HWND child  = (HWND)(void *)(uintptr_t)strtoull(windowId.c_str(), nullptr, 10);
  HWND parent = (HWND)(void *)(uintptr_t)strtoull(parentWindowId.c_str(), nullptr, 10);
  RECT crect; GetClientRect(parent, &crect);
  MoveWindow(child, 0, 0, crect.right, crect.bottom, true);
  SetWindowLongPtr(child, GWL_STYLE, GetWindowLongPtr(child, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU | WS_POPUP | WS_SIZEBOX) | WS_CHILD);
  SetWindowLongPtr(child, GWL_EXSTYLE, GetWindowLongPtr(child, GWL_EXSTYLE) | WS_EX_TOOLWINDOW);
  SetWindowLongPtr(parent, GWL_STYLE, GetWindowLongPtr(parent, GWL_STYLE) | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
  #elif (defined(__linux__) && !defined(__ANDROID__)) || (defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__))
  Window child  = (Window)(uintptr_t)strtoull(windowId.c_str(), nullptr, 10);
  Window parent = (Window)(uintptr_t)strtoull(parentWindowId.c_str(), nullptr, 10);
  Display *display = XOpenDisplay(nullptr); XMapWindow(display, child);
  Window r = 0; int x = 0, y = 0; unsigned w = 0, h = 0, b = 0, d = 0;
  XGetGeometry(display, parent, &r, &x, &y, &w, &h, &b, &d);
  XMoveResizeWindow(display, child, 0, 0, w, h);
  XCloseDisplay(display);
  #else
  DEBUG_MESSAGE("Unsupported platform for function!", MESSAGE_TYPE::M_INFO);
  #endif
}

It's relatively seamless, especially on Windows. It will embed the game window to fill the launcher's client area. I have a means to close the child process when the launcher exits so you don't have the game continuing to run in the background. You can borrow code from my repository to have that automated in enigma internally so you don't risk people writing stuff wrong and terminating the wrong process id which can be avoided if you let enigma handle that for them. You can also make the step event code fire every step automatically too if you want, that will save the user from having to call it manually.

Please note embedding windows is a very popular extension feature that a lot people want on the GMC and have wanted in their projects ever since even pre-GM6 era to the present.  Over time various existing DLL's either lost their compatibility with the newer versions of GM, links to download them went dead, or the solution was closed source and not written with cross-platform in mind. I was paid $275 USD to write the above code, to put it into perspective, they knew it wasn't much work to write, but insisted to pay me that much because that's how much they wanted it. I think you would make a lot of your users happy for adding this.
5
Off-Topic / Re: What genre of game interests you the most
« Last post by hpg678 on May 09, 2022, 11:06:27 am »
I kinda agree in that today Tower Defense games are considered separate but overall, one must employ strategy........which is why i considered them into that category.

Another genre i forgot to include is Board games.
6
Off-Topic / Re: What genre of game interests you the most
« Last post by HitCoder on May 08, 2022, 12:54:17 pm »
This is quite an interesting poll!

Personally I would have made strategy and tower defense two separate categories as I can enjoy tower defense but I don't enjoy most other strategy games :P
7
Off-Topic / What genre of game interests you the most
« Last post by hpg678 on May 08, 2022, 09:26:04 am »
I'm taking this poll in an attempt to comprehend what type of tutorial/game would be good to make/outline using Enigma. Please answer as honestly as possible and if i have missed out a category, then tell me which should have been included.
even if you are not a full 'gamer', there must be some you do play.

thanks!
8
General ENIGMA / Re: enigma-dev-git package on Arch User Repository updated
« Last post by HitCoder on May 03, 2022, 10:24:38 am »
I could perhaps change the icon to use the Enigma logo, but I left it as the LGM logo for now as that's the IDE being used. I'm not sure what the general consensus and preference is there but if the maintainers of the project think it's more appropriate to use the Enigma logo then I'll switch it over :)
9
Off-Topic / Re: What's your favourite Linux/Unix DE/WM and why?
« Last post by hpg678 on May 02, 2022, 01:27:22 pm »
No doubt that KDE is very attractive and sleek but it is bit of a resource hog.

I'm happy with KDE ever since the extremely recent updates making it much more slimmed down and stable.
truth be told, i haven't used KDE for years. It was always XCFE for me even when my system got upgraded. I am inspired to give it another go.

10
General ENIGMA / Re: enigma-dev-git package on Arch User Repository updated
« Last post by hpg678 on May 02, 2022, 01:15:00 pm »
great work.
 I tried it and there were no problems.

It also created a lancher link in the menu......although the icon is an old one. If you could perhaps change it to the modern one, that would be fantastic
 (Y) (Y) (Y) (Y)
Pages: 1 2 3 4 5 6 7 8 9 10