feat(RayFEM): initial commit

This commit is contained in:
2026-02-05 07:16:15 -05:00
commit 0f341071f4
31 changed files with 2973 additions and 0 deletions

111
.gitignore vendored Normal file
View File

@@ -0,0 +1,111 @@
# Python
__pycache__/
*.py[cod]
*.pyo
*.pyd
*.env
*.venv
env/
venv/
ENV/
ENV.bak/
*.egg-info/
dist/
build/
*.egg
# C and C++ (using Meson)
build/
*.o
*.a
*.so
*.d
*.dSYM/
*.exe
*.out
*.obj
*.dll
*.lib
*.pdb
*.exp
*.log
*.stackdump
# Fortran
*.mod
*.o
*.a
*.so
*.exe
*.out
# Doxygen
html/
latex/
xml/
man/
rtf/
tags
## Misc
*.swp
*._DS_Store
*.DS_Store
*.bak
*.tmp
*.log
*.cache
*.private
*.private/
subprojects/mfem/
subprojects/tetgen/
subprojects/yaml-cpp/
subprojects/quill/
subprojects/googletest-*/
subprojects/opat-core/
subprojects/pybind11*/
subprojects/packagecache/
subprojects/hypre/
subprojects/qhull/
subprojects/libconstants/
subprojects/liblogging/
subprojects/libconfig/
subprojects/libcomposition/
subprojects/GridFire/
subprojects/tomlplusplus-*/
subprojects/CLI11-*/
subprojects/magic_enum-*/
subprojects/raylib/
subprojects/czmq/
qhull.wrap
quill.wrap
yaml-cpp.wrap
cppad.wrap
tomlplusplus.wrap
gtest.wrap
subprojects/quill.wrap
.vscode/
*.log
mpi-install-log.txt
output/
.boost_installed
4DSSE_logs/
.last_build_flags
.idea/
scratch/
releases/
stroid-dist/
stroid-universal-dist.tar.gz
stroid-*/
stroid-*.tar.gz

View File

@@ -0,0 +1,2 @@
cli11_proj = subproject('cli11')
dependencies += cli11_proj.get_variable('CLI11_dep')

View File

@@ -0,0 +1,12 @@
czmq_opts = cmake.subproject_options()
czmq_opts.add_cmake_defines({
'CMAKE_POLICY_VERSION_MINIMUM': '3.5',
'CMAKE_C_FLAGS': '-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0',
'CMAKE_CXX_FLAGS': '-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0'
})
czmq_opts.set_install(false)
czmq_subproject = cmake.subproject('czmq', options: czmq_opts)
dependencies += czmq_subproject.dependency('czmq')

View File

@@ -0,0 +1,8 @@
config_p = subproject('libconfig',
default_options:[
'default_library=static',
'pkg_config=false',
'build_tests=false',
'build_examples=false'
])
dependencies += config_p.get_variable('config_dep')

7
build-config/meson.build Normal file
View File

@@ -0,0 +1,7 @@
cmake = import('cmake')
subdir('raylib')
subdir('czmq')
subdir('mfem')
subdir('CLI11')
subdir('libconfig')

View File

@@ -0,0 +1,16 @@
cmake = import('cmake')
mfem_cmake_options = cmake.subproject_options()
mfem_cmake_options.add_cmake_defines({
'MFEM_ENABLE_EXAMPLES': 'OFF',
'MFEM_ENABLE_TESTING': 'OFF',
'MFEM_ENABLE_MINIAPPS': 'OFF',
'MFEM_USE_BENCMARK': 'OFF',
'BUILD_SHARED_LIBS': 'OFF',
'BUILD_STATIC_LIBS': 'ON',
})
mfem_cmake_options.set_install(true)
mfem_sp = cmake.subproject(
'mfem',
options: mfem_cmake_options)
dependencies += mfem_sp.dependency('mfem')

View File

@@ -0,0 +1,39 @@
raylib_opts = cmake.subproject_options()
raylib_opts.set_install(false)
raylib_opts.add_cmake_defines({
'BUILD_EXAMPLES': 'OFF',
})
if cc.get_id() == 'emscripten'
raylib_opts.add_cmake_defines({
'PLATFORM': 'Web',
})
else
raylib_opts.add_cmake_defines({
'PLATFORM': 'Desktop',
})
endif
raylib_subproject = cmake.subproject('raylib', options: raylib_opts)
dependencies += raylib_subproject.dependency('raylib')
# General configuration
if host_machine.system() == 'windows'
dependencies += [
cc.find_library('winmm'),
]
elif host_machine.system() == 'darwin'
link_args += [
'-framework', 'AppKit',
'-framework', 'IOKit',
]
elif host_machine.system() == 'linux'
dependencies += [
cc.find_library('m'),
cc.find_library('dl'),
]
elif host_machine.system() == 'emscripten'
link_args += [
'-s', 'ENVIRONMENT=web',
'-s', 'USE_GLFW=3',
]
name_suffix = 'html'
endif

10
default.toml Normal file
View File

@@ -0,0 +1,10 @@
[main]
core_steepness = 1.0
flattening = 0.0
include_external_domain = false
order = 1
r_core = 1.5
r_infinity = 6.0
r_instability = 1e-14
r_star = 5.0
refinement_levels = 2

17
meson.build Normal file
View File

@@ -0,0 +1,17 @@
project('RayFEM', ['cpp', 'c'],
version : '0.1.0',
default_options : ['warning_level=3', 'cpp_std=c++23'])
c_args = []
cpp_args = []
link_args = []
name_suffix = []
dependencies = []
add_project_arguments('-U_FORTIFY_SOURCE', '-D_FORTIFY_SOURCE=0', language: 'cpp')
cc = meson.get_compiler('c')
cxx = meson.get_compiler('cpp')
subdir('build-config')
subdir('src')

41
src/app/client.cpp Normal file
View File

@@ -0,0 +1,41 @@
#include "libRayfem/network/client.hpp"
#include "mfem.hpp"
#include "fourdst/config/config.h"
#include "CLI/CLI.hpp"
#include <print>
struct config {
std::string host = "localhost";
int port = 5555;
std::string mesh_file = "stroid.mesh";
};
int main(int argc, char** argv) {
fourdst::config::Config<config> cfg;
CLI::App app{"RayFEM Client"};
fourdst::config::register_as_cli(cfg, app, "config");
CLI11_PARSE(app, argc, argv)
auto mesh = std::make_unique<mfem::Mesh>(cfg->mesh_file.c_str());
mesh->EnsureNodes();
mfem::FiniteElementSpace fespace(mesh.get(), new mfem::H1_FECollection(1, mesh->Dimension()), 1);
mfem::GridFunction gf(&fespace);
gf = 0.5;
RayFEM::Client client(cfg->host, cfg->port);
RayFEM::FrameMetadata meta;
meta.frame_index = 0;
meta.sim_time = 0.0;
if (client.send(*mesh, gf, meta)) {
std::println("Frame sent successfully.");
} else {
std::println("Failed to send frame.");
}
return 0;
}

50
src/app/main.cpp Normal file
View File

@@ -0,0 +1,50 @@
#include <print>
#include "raylib.h"
#include "libRayfem/network/server.hpp"
#include "fourdst/config/config.h"
#include "CLI/CLI.hpp"
#include "czmq.h"
struct Options {
std::string listen = "0.0.0.0";
int port = 5555;
int target_fps = 60;
int screenwidth = 800;
int screenheight = 600;
};
int main(int argc, char** argv) {
zsys_init();
fourdst::config::Config<Options> config;
CLI::App app{"RayFEM Server"};
fourdst::config::register_as_cli(config, app, "config");
CLI11_PARSE(app, argc, argv)
const int screenwidth = config->screenwidth;
const int screenheight = config->screenheight;
InitWindow(screenwidth, screenheight, "raylib");
SetTargetFPS(config->target_fps);
RayFEM::Server server(config->listen, config->port);
bool hasRecivedData = false;
while (!WindowShouldClose()) {
auto frame = server.fetchLatestFrame();
if (frame) {
hasRecivedData = true;
}
BeginDrawing();
ClearBackground(RAYWHITE);
std::string msg = std::format("Has Received {} frames", server.getReceivedFrameCount());
DrawText(msg.c_str(), 250, 280, 20, DARKGREEN);
EndDrawing();
}
CloseWindow();
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include "mfem.hpp"
#include "raylib.h"
#include <memory>
#include "libRayfem/network/packet.hpp"
namespace RayFEM {
struct RenderFrame {
FrameMetadata metadata;
std::unique_ptr<mfem::Mesh> mesh;
std::unique_ptr<mfem::GridFunction> gf;
Model rayModel;
bool isUploaded = false;
};
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include "raylib.h"
#include "mfem.hpp"
namespace RayFEM {
Model LoadModelFromMFEM(mfem::Mesh& mesh, mfem::GridFunction& gf);
}

View File

@@ -0,0 +1,20 @@
#pragma once
#include <string>
#include "mfem.hpp"
#include "libRayfem/network/packet.hpp"
#include "zmq.hpp"
namespace RayFEM {
class Client {
public:
Client(const std::string& host, size_t port);
bool send(mfem::Mesh& mesh, mfem::GridFunction& gf, const FrameMetadata& meta);
private:
std::string m_host;
size_t m_port;
std::string m_address;
SocketPtr m_socket;
};
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include <cstdint>
namespace RayFEM {
struct FrameMetadata {
uint32_t frame_index = 0;
double sim_time = 0;
char label[64] = "MFEM Simulation";
};
#pragma pack(push, 1)
struct PacketHeader {
uint64_t magic = 0x52415946454D;
FrameMetadata metadata;
uint64_t mesh_bytes = 0;
uint64_t gf_bytes = 0;
};
#pragma pack(pop)
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include <memory>
#include <cstdint>
#include <atomic>
#include <thread>
#include <mutex>
#include <deque>
#include <optional>
#include "libRayfem/frame/render.hpp"
namespace RayFEM {
class Server {
public:
Server(const std::string& listen, size_t port);
~Server();
std::unique_ptr<RenderFrame> fetchLatestFrame();
size_t getReceivedFrameCount() const { return m_frameCount.load(); }
private:
std::string m_listen;
int m_port;
std::atomic<bool> m_running;
std::atomic<size_t> m_frameCount{0};
std::thread m_worker;
std::mutex m_mutex;
std::deque<std::unique_ptr<RenderFrame>> m_frameQueue;
private:
void networkLoop();
};
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include "czmq.h"
namespace RayFEM {
template <typename T, void (*Destroyer)(T**)>
class ZmqPtr {
public:
ZmqPtr(T* ptr = nullptr) : ptr_(ptr) {}
~ZmqPtr() { if (ptr_) Destroyer(&ptr_); }
ZmqPtr(const ZmqPtr&) = delete;
ZmqPtr& operator=(const ZmqPtr&) = delete;
ZmqPtr(ZmqPtr&& other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
ZmqPtr& operator=(ZmqPtr&& other) noexcept {
if (this != &other) {
if (ptr_) Destroyer(&ptr_);
ptr_ = other.ptr_;
other.ptr_ = nullptr;
}
return *this;
}
T* release() {
T* temp = ptr_;
ptr_ = nullptr;
return temp;
}
T* get() const { return ptr_; }
operator T*() const { return ptr_; }
T** operator&() { return &ptr_; }
private:
T* ptr_ = nullptr;
};
using SocketPtr = ZmqPtr<zsock_t, zsock_destroy>;
using MsgPtr = ZmqPtr<zmsg_t, zmsg_destroy>;
using FramePtr = ZmqPtr<zframe_t, zframe_destroy>;
}

View File

@@ -0,0 +1,118 @@
#include "libRayfem/mesh/converter.hpp"
#include "mfem.hpp"
#include "raylib.h"
namespace {
Color GetColorFromValue(double val, double min, double max) {
double t = (val - min) / (max - min);
t = std::clamp(t, 0.0, 1.0);
return ColorFromNormalized({t, 1-t, 0.5+(t*0.5), 1};
}
}
namespace RayFEM {
Model LoadModelFromMFEM(mfem::Mesh &mesh, mfem::GridFunction &gf) {
Mesh rMesh = { 0 };
int numElements = mesh.GetNE();
int totalTriangles = 0;
for (int i = 0; i < numElements; i++) {
mfem::Geometry::Type geom = mesh.GetElementBaseGeometry(i);
switch (geom) {
case mfem::Geometry::TRIANGLE:
totalTriangles += 1;
break;
case mfem::Geometry::SQUARE:
totalTriangles += 2;
break;
case mfem::Geometry::TETRAHEDRON:
totalTriangles += 4;
break;
case mfem::Geometry::CUBE:
totalTriangles += 12;
break;
default:
throw std::runtime_error("Unsupported element geometry in MFEM to Raylib converter.");
}
}
rMesh.triangleCount = totalTriangles;
rMesh.vertexCount = rMesh.triangleCount * 3;
rMesh.vertices = (float *)RL_MALLOC(rMesh.vertexCount * 3 * sizeof(float));
rMesh.colors = (unsigned char *)RL_MALLOC(rMesh.vertexCount * 4 * sizeof(unsigned char));
double vMin = gf.Min();
double vMax = gf.Max();
int vOffset =0;
auto AddTriangle = [&](const mfem::Vector& p1, const mfem::Vector& p2, const mfem::Vector& p3, double val1, double val2, double val3) {
float* v = rMesh.vertices;
v[vOffset * 3 + 0] = static_cast<float>(p1(0));
v[vOffset * 3 + 1] = static_cast<float>(p1(1));
v[vOffset * 3 + 2] = static_cast<float>(p1(2));
v[vOffset * 3 + 3] = static_cast<float>(p2(0));
v[vOffset * 3 + 4] = static_cast<float>(p2(1));
v[vOffset * 3 + 5] = static_cast<float>(p2(2));
v[vOffset * 3 + 6] = static_cast<float>(p3(0));
v[vOffset * 3 + 7] = static_cast<float>(p3(1));
v[vOffset * 3 + 8] = static_cast<float>(p3(2));
const Color c1 = GetColorFromValue(val1, vMin, vMax);
const Color c2 = GetColorFromValue(val2, vMin, vMax);
const Color c3 = GetColorFromValue(val3, vMin, vMax);
unsigned char* c = rMesh.colors;
c[vOffset * 4 + 0] = c1.r;
c[vOffset * 4 + 1] = c1.g;
c[vOffset * 4 + 2] = c1.b;
c[vOffset * 4 + 3] = c1.a;
c[vOffset * 4 + 4] = c2.r;
c[vOffset * 4 + 5] = c2.g;
c[vOffset * 4 + 6] = c2.b;
c[vOffset * 4 + 7] = c2.a;
c[vOffset * 4 + 8] = c3.r;
c[vOffset * 4 + 9] = c3.g;
c[vOffset * 4 + 10] = c3.b;
c[vOffset * 4 + 11] = c3.a;
vOffset += 3;
};
for (int i = 0; i < numElements; i++) {
mfem::Element* el = mesh.GetElement(i);
mfem::Array<int> verticies;
mesh.GetElementVertices(i, verticies);
auto GetPV = [&](int localIdx) {
mfem::Vector pos;
pos = mesh.GetVertex(verticies[localIdx]);
if (pos.Size() == 2) {
pos.SetSize(3);
pos(2) = 0.0;
}
return std::make_pair(pos, gf(verticies[localIdx]));
};
mfem::Geometry::Type geom = mesh.GetElementBaseGeometry(i);
switch (geom) {
case mfem::Geometry::TRIANGLE: {
auto [p0, v0] = GetPV(0);
auto [p1, v1] = GetPV(1);
auto [p2, v2] = GetPV(2);
AddTriangle(p0, p1, p2, v0, v1, v2);
}
}
}
}
}

View File

@@ -0,0 +1,57 @@
#include "libRayfem/network/client.hpp"
#include "libRayfem/network/zmq.hpp"
#include "libRayfem/network/packet.hpp"
#include "czmq.h"
#include <string>
namespace {
std::string format_address(const std::string& host, const size_t port) {
return "tcp://" + host + ":" + std::to_string(port);
}
}
namespace RayFEM {
Client::Client(
const std::string &host,
const size_t port
)
:
m_host(host),
m_port(port),
m_address(format_address(m_host, m_port)),
m_socket(zsock_new_push(m_address.c_str())) {
if (!m_socket) {
throw std::runtime_error("Failed to create ZMQ socket to " + m_address);
}
zsock_set_linger(m_socket, 1000);
}
bool Client::send(mfem::Mesh &mesh, mfem::GridFunction &gf, const FrameMetadata& meta) {
if (!m_socket) {
return false;
}
std::stringstream m_ss, g_ss;
mesh.Print(m_ss);
gf.Save(g_ss);
std::string m_data = m_ss.str();
std::string g_data = g_ss.str();
MsgPtr msg(zmsg_new());
PacketHeader header{.metadata = meta, .mesh_bytes = m_data.size(), .gf_bytes = g_data.size()};
zmsg_addmem(msg, &header, sizeof(PacketHeader));
zmsg_addstr(msg, m_data.c_str());
zmsg_addstr(msg, g_data.c_str());
zmsg_t* raw_msg = msg.get();
int rc = zmsg_send(&raw_msg, m_socket);
msg.release();
return rc == 0;
}
}

View File

@@ -0,0 +1,95 @@
#include "libRayfem/frame/render.hpp"
#include "libRayfem/network/server.hpp"
#include "libRayfem/network/zmq.hpp"
#include <optional>
#include <thread>
#include <mutex>
#include <deque>
#include "czmq.h"
namespace RayFEM {
Server::Server(
const std::string& listen,
const size_t port
) :
m_listen(listen),
m_port(port),
m_running(true),
m_worker(std::thread(&Server::networkLoop, this)) {}
Server::~Server() {
m_running = false;
if (m_worker.joinable()) {
m_worker.join();
}
}
std::unique_ptr<RenderFrame> Server::fetchLatestFrame() {
std::lock_guard<std::mutex> lock(m_mutex);
if (m_frameQueue.empty()) return nullptr;
auto frame = std::move(m_frameQueue.back());
m_frameQueue.clear();
return frame;
}
void Server::networkLoop() {
std::string address = "tcp://" + m_listen + ":" + std::to_string(m_port);
SocketPtr pull(zsock_new_pull(address.c_str()));
zpoller_t *poller = zpoller_new(pull.get(), NULL);
while (m_running) {
void *which = zpoller_wait(poller, 100);
if (!which) continue;
MsgPtr msg(zmsg_recv(pull.get()));
if (!msg) continue;
auto frame = std::make_unique<RenderFrame>();
zframe_t *h_frame = zmsg_pop(msg.get());
if (zframe_size(h_frame) == sizeof(PacketHeader)) {
frame->metadata = reinterpret_cast<PacketHeader *>(zframe_data(h_frame))->metadata;
}
zframe_destroy(&h_frame);
zframe_t *m_frame = zmsg_pop(msg.get());
zframe_t *g_frame = zmsg_pop(msg.get());
if (m_frame && g_frame) {
std::string m_data(reinterpret_cast<char *>(zframe_data(m_frame)), zframe_size(m_frame));
std::string g_data(reinterpret_cast<char *>(zframe_data(g_frame)), zframe_size(g_frame));
std::cout << g_data << std::endl;
std::stringstream m_ss(m_data);
std::stringstream g_ss(g_data);
try {
frame->mesh = std::make_unique<mfem::Mesh>(m_ss);
frame->mesh->EnsureNodes();
frame->gf = std::make_unique<mfem::GridFunction>(frame->mesh.get(), g_ss);
} catch (...) {
std::cerr << "Error creating mesh frame" << std::endl;
}
++m_frameCount;
{
std::lock_guard<std::mutex> lock(m_mutex);
m_frameQueue.push_back(std::move(frame));
}
}
zframe_destroy(&m_frame);
zframe_destroy(&g_frame);
}
zpoller_destroy(&poller);
}
}

23
src/libRayfem/meson.build Normal file
View File

@@ -0,0 +1,23 @@
include_dirs = include_directories('include')
sources = files(
'lib/network/client.cpp',
'lib/network/server.cpp',
'lib/mesh/converter.cpp'
)
libRayFem = library(
'libRayFem',
sources,
include_directories: include_dirs,
dependencies: dependencies,
cpp_args: cpp_args,
install: true
)
rayfem_dep = declare_dependency(
include_directories: include_dirs,
link_with: libRayFem,
sources: sources,
dependencies: dependencies,
compile_args: cpp_args,
)

17
src/meson.build Normal file
View File

@@ -0,0 +1,17 @@
subdir('libRayFem')
executable(
'RayFEM',
'app/main.cpp',
dependencies: [dependencies, rayfem_dep],
cpp_args: cpp_args,
c_args: c_args,
link_args: link_args
)
executable(
'exampleClient',
'app/client.cpp',
dependencies: [dependencies, rayfem_dep],
cpp_args: cpp_args,
c_args: c_args,
link_args: link_args
)

2128
stroid.mesh Normal file

File diff suppressed because it is too large Load Diff

0
subprojects/.wraplock Normal file
View File

10
subprojects/cli11.wrap Normal file
View File

@@ -0,0 +1,10 @@
[wrap-file]
directory = CLI11-2.6.1
source_url = https://github.com/CLIUtils/CLI11/archive/refs/tags/v2.6.1.tar.gz
source_filename = CLI11-2.6.1.tar.gz
source_hash = 377691f3fac2b340f12a2f79f523c780564578ba3d6eaf5238e9f35895d5ba95
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/cli11_2.6.1-1/CLI11-2.6.1.tar.gz
wrapdb_version = 2.6.1-1
[provide]
dependency_names = CLI11

6
subprojects/czmq.wrap Normal file
View File

@@ -0,0 +1,6 @@
[wrap-git]
url = https://github.com/zeromq/czmq
revision = v4.2.1
depth = 1
[cmake]

View File

@@ -0,0 +1,4 @@
[wrap-git]
url = https://github.com/4D-STAR/libconfig.git
revision = v2.1.0
depth = 1

7
subprojects/mfem.wrap Normal file
View File

@@ -0,0 +1,7 @@
[wrap-git]
url = https://github.com/mfem/mfem.git
revision = v4.8-rc0
diff_files = mfem/disable_mfem_selfcheck.patch
depth = 1
[cmake]

View File

@@ -0,0 +1,6 @@
# subprojects/packagefiles/hypre/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(hypre-wrapper C CXX)
add_subdirectory(src)
# This file is just used to redirect to the src directory where hypre stores its CMakeLists.txt

View File

@@ -0,0 +1,41 @@
--- mfem/CMakeLists.txt 2025-02-12 15:54:52.454728232 -0500
+++ CMakeLists.txt.bak 2025-02-12 16:08:06.654542689 -0500
@@ -765,7 +765,7 @@
if (MFEM_ENABLE_EXAMPLES)
add_subdirectory(examples) #install examples if enabled
else()
- add_subdirectory(examples EXCLUDE_FROM_ALL)
+ # add_subdirectory(examples EXCLUDE_FROM_ALL)
endif()
# Create a target for all miniapps and, optionally, enable it.
@@ -774,7 +774,7 @@
if (MFEM_ENABLE_MINIAPPS)
add_subdirectory(miniapps) #install miniapps if enabled
else()
- add_subdirectory(miniapps EXCLUDE_FROM_ALL)
+ # add_subdirectory(miniapps EXCLUDE_FROM_ALL)
endif()
# Target to build all executables, i.e. everything.
@@ -801,19 +801,7 @@
add_dependencies(${MFEM_EXEC_PREREQUISITES_TARGET_NAME} copy_data)
endif()
-# Add 'check' target - quick test
-set(MFEM_CHECK_TARGET_NAME ${MFEM_CUSTOM_TARGET_PREFIX}check)
-if (NOT MFEM_USE_MPI)
- add_custom_target(${MFEM_CHECK_TARGET_NAME}
- ${CMAKE_CTEST_COMMAND} -R \"^ex1_ser\" -C ${CMAKE_CFG_INTDIR}
- USES_TERMINAL)
- add_dependencies(${MFEM_CHECK_TARGET_NAME} ex1)
-else()
- add_custom_target(${MFEM_CHECK_TARGET_NAME}
- ${CMAKE_CTEST_COMMAND} -R \"^ex1p\" -C ${CMAKE_CFG_INTDIR}
- USES_TERMINAL)
- add_dependencies(${MFEM_CHECK_TARGET_NAME} ex1p)
-endif()
+message(STATUS "MFEM Miniapps and Examples disabled by patch!")
#-------------------------------------------------------------------------------
# Documentation

6
subprojects/raylib.wrap Normal file
View File

@@ -0,0 +1,6 @@
[wrap-git]
url = https://github.com/raysan5/raylib.git
revision = 5.5
depth = 1
[cmake]