This commit is contained in:
jiegeaiai 2024-11-30 22:26:28 +08:00
parent fcf8cfc7f4
commit 25c023e479
31 changed files with 1539 additions and 53 deletions

View File

@ -0,0 +1,68 @@
#pragma once
#include <cstddef>
#include <tuple>
#include <vector>
#include <type_traits>
#include "libipc/export.h"
#include "libipc/def.h"
namespace ipc {
class IPC_EXPORT buffer {
public:
using destructor_t = void (*)(void*, std::size_t);
buffer();
buffer(void* p, std::size_t s, destructor_t d);
buffer(void* p, std::size_t s, destructor_t d, void* additional);
buffer(void* p, std::size_t s);
template <std::size_t N>
explicit buffer(byte_t const (& data)[N])
: buffer(data, sizeof(data)) {
}
explicit buffer(char const & c);
buffer(buffer&& rhs);
~buffer();
void swap(buffer& rhs);
buffer& operator=(buffer rhs);
bool empty() const noexcept;
void * data() noexcept;
void const * data() const noexcept;
template <typename T>
T get() const { return T(data()); }
std::size_t size() const noexcept;
std::tuple<void*, std::size_t> to_tuple() {
return std::make_tuple(data(), size());
}
std::tuple<void const *, std::size_t> to_tuple() const {
return std::make_tuple(data(), size());
}
std::vector<byte_t> to_vector() const {
return {
get<byte_t const *>(),
get<byte_t const *>() + size()
};
}
friend IPC_EXPORT bool operator==(buffer const & b1, buffer const & b2);
friend IPC_EXPORT bool operator!=(buffer const & b1, buffer const & b2);
private:
class buffer_;
buffer_* p_;
};
} // namespace ipc

View File

@ -0,0 +1,39 @@
#pragma once
#include <cstdint> // std::uint64_t
#include "libipc/export.h"
#include "libipc/def.h"
#include "libipc/mutex.h"
namespace ipc {
namespace sync {
class IPC_EXPORT condition {
condition(condition const &) = delete;
condition &operator=(condition const &) = delete;
public:
condition();
explicit condition(char const *name);
~condition();
void const *native() const noexcept;
void *native() noexcept;
bool valid() const noexcept;
bool open(char const *name) noexcept;
void close() noexcept;
bool wait(ipc::sync::mutex &mtx, std::uint64_t tm = ipc::invalid_value) noexcept;
bool notify() noexcept;
bool broadcast() noexcept;
private:
class condition_;
condition_* p_;
};
} // namespace sync
} // namespace ipc

68
Thirdparty/libipc/include/libipc/def.h vendored Normal file
View File

@ -0,0 +1,68 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <limits> // std::numeric_limits
#include <new>
#include <utility>
namespace ipc {
// types
using byte_t = std::uint8_t;
template <std::size_t N>
struct uint;
template <> struct uint<8 > { using type = std::uint8_t ; };
template <> struct uint<16> { using type = std::uint16_t; };
template <> struct uint<32> { using type = std::uint32_t; };
template <> struct uint<64> { using type = std::uint64_t; };
template <std::size_t N>
using uint_t = typename uint<N>::type;
// constants
enum : std::uint32_t {
invalid_value = (std::numeric_limits<std::uint32_t>::max)(),
default_timeout = 100, // ms
};
enum : std::size_t {
data_length = 64,
large_msg_limit = data_length,
large_msg_align = 1024,
large_msg_cache = 32,
};
enum class relat { // multiplicity of the relationship
single,
multi
};
enum class trans { // transmission
unicast,
broadcast
};
// producer-consumer policy flag
template <relat Rp, relat Rc, trans Ts>
struct wr {};
template <typename WR>
struct relat_trait;
template <relat Rp, relat Rc, trans Ts>
struct relat_trait<wr<Rp, Rc, Ts>> {
constexpr static bool is_multi_producer = (Rp == relat::multi);
constexpr static bool is_multi_consumer = (Rc == relat::multi);
constexpr static bool is_broadcast = (Ts == trans::broadcast);
};
template <template <typename> class Policy, typename Flag>
struct relat_trait<Policy<Flag>> : relat_trait<Flag> {};
} // namespace ipc

View File

@ -0,0 +1,54 @@
#pragma once
#if defined(Q_DECL_EXPORT) && defined(Q_DECL_IMPORT)
# define IPC_DECL_EXPORT Q_DECL_EXPORT
# define IPC_DECL_IMPORT Q_DECL_IMPORT
#else // defined(Q_DECL_EXPORT) && defined(Q_DECL_IMPORT)
/*
* Compiler & system detection for IPC_DECL_EXPORT & IPC_DECL_IMPORT.
* Not using QtCore cause it shouldn't depend on Qt.
*/
#if defined(_MSC_VER)
# define IPC_DECL_EXPORT __declspec(dllexport)
# define IPC_DECL_IMPORT __declspec(dllimport)
#elif defined(__ARMCC__) || defined(__CC_ARM)
# if defined(ANDROID) || defined(__linux__) || defined(__linux)
# define IPC_DECL_EXPORT __attribute__((visibility("default")))
# define IPC_DECL_IMPORT __attribute__((visibility("default")))
# else
# define IPC_DECL_EXPORT __declspec(dllexport)
# define IPC_DECL_IMPORT __declspec(dllimport)
# endif
#elif defined(__GNUC__)
# if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \
defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
# define IPC_DECL_EXPORT __declspec(dllexport)
# define IPC_DECL_IMPORT __declspec(dllimport)
# else
# define IPC_DECL_EXPORT __attribute__((visibility("default")))
# define IPC_DECL_IMPORT __attribute__((visibility("default")))
# endif
#else
# define IPC_DECL_EXPORT __attribute__((visibility("default")))
# define IPC_DECL_IMPORT __attribute__((visibility("default")))
#endif
#endif // defined(Q_DECL_EXPORT) && defined(Q_DECL_IMPORT)
/*
* Define IPC_EXPORT for exporting function & class.
*/
#ifndef IPC_EXPORT
#if defined(LIBIPC_LIBRARY_SHARED_BUILDING__)
# define IPC_EXPORT IPC_DECL_EXPORT
#elif defined(LIBIPC_LIBRARY_SHARED_USING__)
# define IPC_EXPORT IPC_DECL_IMPORT
#else
# define IPC_EXPORT
#endif
#endif /*IPC_EXPORT*/

192
Thirdparty/libipc/include/libipc/ipc.h vendored Normal file
View File

@ -0,0 +1,192 @@
#pragma once
#include <string>
#include "libipc/export.h"
#include "libipc/def.h"
#include "libipc/buffer.h"
#include "libipc/shm.h"
namespace ipc {
using handle_t = void*;
using buff_t = buffer;
enum : unsigned {
sender,
receiver
};
template <typename Flag>
struct IPC_EXPORT chan_impl {
static bool connect (ipc::handle_t * ph, char const * name, unsigned mode);
static bool reconnect (ipc::handle_t * ph, unsigned mode);
static void disconnect(ipc::handle_t h);
static void destroy (ipc::handle_t h);
static char const * name(ipc::handle_t h);
static std::size_t recv_count(ipc::handle_t h);
static bool wait_for_recv(ipc::handle_t h, std::size_t r_count, std::uint64_t tm);
static bool send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm);
static buff_t recv(ipc::handle_t h, std::uint64_t tm);
static bool try_send(ipc::handle_t h, void const * data, std::size_t size, std::uint64_t tm);
static buff_t try_recv(ipc::handle_t h);
};
template <typename Flag>
class chan_wrapper {
private:
using detail_t = chan_impl<Flag>;
ipc::handle_t h_ = nullptr;
unsigned mode_ = ipc::sender;
bool connected_ = false;
public:
chan_wrapper() noexcept = default;
explicit chan_wrapper(char const * name, unsigned mode = ipc::sender)
: connected_{this->connect(name, mode)} {
}
chan_wrapper(chan_wrapper&& rhs) noexcept
: chan_wrapper{} {
swap(rhs);
}
~chan_wrapper() {
detail_t::destroy(h_);
}
void swap(chan_wrapper& rhs) noexcept {
std::swap(h_ , rhs.h_);
std::swap(mode_ , rhs.mode_);
std::swap(connected_, rhs.connected_);
}
chan_wrapper& operator=(chan_wrapper rhs) noexcept {
swap(rhs);
return *this;
}
char const * name() const noexcept {
return detail_t::name(h_);
}
ipc::handle_t handle() const noexcept {
return h_;
}
bool valid() const noexcept {
return (handle() != nullptr);
}
unsigned mode() const noexcept {
return mode_;
}
chan_wrapper clone() const {
return chan_wrapper { name(), mode_ };
}
/**
* Building handle, then try connecting with name & mode flags.
*/
bool connect(char const * name, unsigned mode = ipc::sender | ipc::receiver) {
if (name == nullptr || name[0] == '\0') return false;
detail_t::disconnect(h_); // clear old connection
return connected_ = detail_t::connect(&h_, name, mode_ = mode);
}
/**
* Try connecting with new mode flags.
*/
bool reconnect(unsigned mode) {
if (!valid()) return false;
if (connected_ && (mode_ == mode)) return true;
return connected_ = detail_t::reconnect(&h_, mode_ = mode);
}
void disconnect() {
if (!valid()) return;
detail_t::disconnect(h_);
connected_ = false;
}
std::size_t recv_count() const {
return detail_t::recv_count(h_);
}
bool wait_for_recv(std::size_t r_count, std::uint64_t tm = invalid_value) const {
return detail_t::wait_for_recv(h_, r_count, tm);
}
static bool wait_for_recv(char const * name, std::size_t r_count, std::uint64_t tm = invalid_value) {
return chan_wrapper(name).wait_for_recv(r_count, tm);
}
/**
* If timeout, this function would call 'force_push' to send the data forcibly.
*/
bool send(void const * data, std::size_t size, std::uint64_t tm = default_timeout) {
return detail_t::send(h_, data, size, tm);
}
bool send(buff_t const & buff, std::uint64_t tm = default_timeout) {
return this->send(buff.data(), buff.size(), tm);
}
bool send(std::string const & str, std::uint64_t tm = default_timeout) {
return this->send(str.c_str(), str.size() + 1, tm);
}
/**
* If timeout, this function would just return false.
*/
bool try_send(void const * data, std::size_t size, std::uint64_t tm = default_timeout) {
return detail_t::try_send(h_, data, size, tm);
}
bool try_send(buff_t const & buff, std::uint64_t tm = default_timeout) {
return this->try_send(buff.data(), buff.size(), tm);
}
bool try_send(std::string const & str, std::uint64_t tm = default_timeout) {
return this->try_send(str.c_str(), str.size() + 1, tm);
}
buff_t recv(std::uint64_t tm = invalid_value) {
return detail_t::recv(h_, tm);
}
buff_t try_recv() {
return detail_t::try_recv(h_);
}
};
template <relat Rp, relat Rc, trans Ts>
using chan = chan_wrapper<ipc::wr<Rp, Rc, Ts>>;
/**
* class route
*
* You could use one producer/server/sender for sending messages to a route,
* then all the consumers/clients/receivers which are receiving with this route,
* would receive your sent messages.
*
* A route could only be used in 1 to N
* (one producer/writer to multi consumers/readers)
*/
using route = chan<relat::single, relat::multi, trans::broadcast>;
/**
* class channel
*
* You could use multi producers/writers for sending messages to a channel,
* then all the consumers/readers which are receiving with this channel,
* would receive your sent messages.
*/
using channel = chan<relat::multi, relat::multi, trans::broadcast>;
} // namespace ipc

View File

@ -0,0 +1,39 @@
#pragma once
#include <cstdint> // std::uint64_t
#include <system_error>
#include "libipc/export.h"
#include "libipc/def.h"
namespace ipc {
namespace sync {
class IPC_EXPORT mutex {
mutex(mutex const &) = delete;
mutex &operator=(mutex const &) = delete;
public:
mutex();
explicit mutex(char const *name);
~mutex();
void const *native() const noexcept;
void *native() noexcept;
bool valid() const noexcept;
bool open(char const *name) noexcept;
void close() noexcept;
bool lock(std::uint64_t tm = ipc::invalid_value) noexcept;
bool try_lock() noexcept(false); // std::system_error
bool unlock() noexcept;
private:
class mutex_;
mutex_* p_;
};
} // namespace sync
} // namespace ipc

View File

@ -0,0 +1,103 @@
#pragma once
#include <new>
#include <utility>
#include "libipc/export.h"
#include "libipc/def.h"
namespace ipc {
namespace mem {
class IPC_EXPORT pool_alloc {
public:
static void* alloc(std::size_t size);
static void free (void* p, std::size_t size);
};
////////////////////////////////////////////////////////////////
/// construct/destruct an object
////////////////////////////////////////////////////////////////
namespace detail {
template <typename T>
struct impl {
template <typename... P>
static T* construct(T* p, P&&... params) {
::new (p) T(std::forward<P>(params)...);
return p;
}
static void destruct(T* p) {
reinterpret_cast<T*>(p)->~T();
}
};
template <typename T, size_t N>
struct impl<T[N]> {
using type = T[N];
template <typename... P>
static type* construct(type* p, P&&... params) {
for (size_t i = 0; i < N; ++i) {
impl<T>::construct(&((*p)[i]), std::forward<P>(params)...);
}
return p;
}
static void destruct(type* p) {
for (size_t i = 0; i < N; ++i) {
impl<T>::destruct(&((*p)[i]));
}
}
};
} // namespace detail
template <typename T, typename... P>
T* construct(T* p, P&&... params) {
return detail::impl<T>::construct(p, std::forward<P>(params)...);
}
template <typename T, typename... P>
T* construct(void* p, P&&... params) {
return construct(static_cast<T*>(p), std::forward<P>(params)...);
}
template <typename T>
void destruct(T* p) {
return detail::impl<T>::destruct(p);
}
template <typename T>
void destruct(void* p) {
destruct(static_cast<T*>(p));
}
////////////////////////////////////////////////////////////////
/// general alloc/free
////////////////////////////////////////////////////////////////
inline void* alloc(std::size_t size) {
return pool_alloc::alloc(size);
}
template <typename T, typename... P>
T* alloc(P&&... params) {
return construct<T>(pool_alloc::alloc(sizeof(T)), std::forward<P>(params)...);
}
inline void free(void* p, std::size_t size) {
pool_alloc::free(p, size);
}
template <typename T>
void free(T* p) {
if (p == nullptr) return;
destruct(p);
pool_alloc::free(p, sizeof(T));
}
} // namespace mem
} // namespace ipc

View File

@ -0,0 +1,171 @@
#pragma once
#include <atomic>
#include <thread>
#include <chrono>
#include <limits>
#include <type_traits>
#include <utility>
////////////////////////////////////////////////////////////////
/// Gives hint to processor that improves performance of spin-wait loops.
////////////////////////////////////////////////////////////////
#pragma push_macro("IPC_LOCK_PAUSE_")
#undef IPC_LOCK_PAUSE_
#if defined(_MSC_VER)
#include <windows.h> // YieldProcessor
/*
See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms687419(v=vs.85).aspx
Not for intel c++ compiler, so ignore http://software.intel.com/en-us/forums/topic/296168
*/
# define IPC_LOCK_PAUSE_() YieldProcessor()
#elif defined(__GNUC__)
#if defined(__i386__) || defined(__x86_64__)
/*
See: Intel(R) 64 and IA-32 Architectures Software Developer's Manual V2
PAUSE-Spin Loop Hint, 4-57
http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.html?wapkw=instruction+set+reference
*/
# define IPC_LOCK_PAUSE_() __asm__ __volatile__("pause")
#elif defined(__ia64__) || defined(__ia64)
/*
See: Intel(R) Itanium(R) Architecture Developer's Manual, Vol.3
hint - Performance Hint, 3:145
http://www.intel.com/content/www/us/en/processors/itanium/itanium-architecture-vol-3-manual.html
*/
# define IPC_LOCK_PAUSE_() __asm__ __volatile__ ("hint @pause")
#elif defined(__arm__)
/*
See: ARM Architecture Reference Manuals (YIELD)
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.architecture.reference/index.html
*/
# define IPC_LOCK_PAUSE_() __asm__ __volatile__ ("yield")
#endif
#endif/*compilers*/
#if !defined(IPC_LOCK_PAUSE_)
/*
Just use a compiler fence, prevent compiler from optimizing loop
*/
# define IPC_LOCK_PAUSE_() std::atomic_signal_fence(std::memory_order_seq_cst)
#endif/*!defined(IPC_LOCK_PAUSE_)*/
////////////////////////////////////////////////////////////////
/// Yield to other threads
////////////////////////////////////////////////////////////////
namespace ipc {
template <typename K>
inline void yield(K& k) noexcept {
if (k < 4) { /* Do nothing */ }
else
if (k < 16) { IPC_LOCK_PAUSE_(); }
else
if (k < 32) { std::this_thread::yield(); }
else {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
return;
}
++k;
}
template <std::size_t N = 32, typename K, typename F>
inline void sleep(K& k, F&& f) {
if (k < static_cast<K>(N)) {
std::this_thread::yield();
}
else {
static_cast<void>(std::forward<F>(f)());
return;
}
++k;
}
template <std::size_t N = 32, typename K>
inline void sleep(K& k) {
sleep<N>(k, [] {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
});
}
} // namespace ipc
#pragma pop_macro("IPC_LOCK_PAUSE_")
namespace ipc {
class spin_lock {
std::atomic<unsigned> lc_ { 0 };
public:
void lock(void) noexcept {
for (unsigned k = 0;
lc_.exchange(1, std::memory_order_acquire);
yield(k)) ;
}
void unlock(void) noexcept {
lc_.store(0, std::memory_order_release);
}
};
class rw_lock {
using lc_ui_t = unsigned;
std::atomic<lc_ui_t> lc_ { 0 };
enum : lc_ui_t {
w_mask = (std::numeric_limits<std::make_signed_t<lc_ui_t>>::max)(), // b 0111 1111
w_flag = w_mask + 1 // b 1000 0000
};
public:
rw_lock() = default;
rw_lock(const rw_lock&) = delete;
rw_lock& operator=(const rw_lock&) = delete;
rw_lock(rw_lock&&) = delete;
rw_lock& operator=(rw_lock&&) = delete;
void lock() noexcept {
for (unsigned k = 0;;) {
auto old = lc_.fetch_or(w_flag, std::memory_order_acq_rel);
if (!old) return; // got w-lock
if (!(old & w_flag)) break; // other thread having r-lock
yield(k); // other thread having w-lock
}
// wait for reading finished
for (unsigned k = 0;
lc_.load(std::memory_order_acquire) & w_mask;
yield(k)) ;
}
void unlock() noexcept {
lc_.store(0, std::memory_order_release);
}
void lock_shared() noexcept {
auto old = lc_.load(std::memory_order_acquire);
for (unsigned k = 0;;) {
// if w_flag set, just continue
if (old & w_flag) {
yield(k);
old = lc_.load(std::memory_order_acquire);
}
// otherwise try cas lc + 1 (set r-lock)
else if (lc_.compare_exchange_weak(old, old + 1, std::memory_order_release)) {
return;
}
// set r-lock failed, old has been updated
}
}
void unlock_shared() noexcept {
lc_.fetch_sub(1, std::memory_order_release);
}
};
} // namespace ipc

View File

@ -0,0 +1,37 @@
#pragma once
#include <cstdint> // std::uint64_t
#include "libipc/export.h"
#include "libipc/def.h"
namespace ipc {
namespace sync {
class IPC_EXPORT semaphore {
semaphore(semaphore const &) = delete;
semaphore &operator=(semaphore const &) = delete;
public:
semaphore();
explicit semaphore(char const *name, std::uint32_t count = 0);
~semaphore();
void const *native() const noexcept;
void *native() noexcept;
bool valid() const noexcept;
bool open(char const *name, std::uint32_t count = 0) noexcept;
void close() noexcept;
bool wait(std::uint64_t tm = ipc::invalid_value) noexcept;
bool post(std::uint32_t count = 1) noexcept;
private:
class semaphore_;
semaphore_* p_;
};
} // namespace sync
} // namespace ipc

59
Thirdparty/libipc/include/libipc/shm.h vendored Normal file
View File

@ -0,0 +1,59 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include "libipc/export.h"
namespace ipc {
namespace shm {
using id_t = void*;
enum : unsigned {
create = 0x01,
open = 0x02
};
IPC_EXPORT id_t acquire(char const * name, std::size_t size, unsigned mode = create | open);
IPC_EXPORT void * get_mem(id_t id, std::size_t * size);
IPC_EXPORT std::int32_t release(id_t id);
IPC_EXPORT void remove (id_t id);
IPC_EXPORT void remove (char const * name);
IPC_EXPORT std::int32_t get_ref(id_t id);
IPC_EXPORT void sub_ref(id_t id);
class IPC_EXPORT handle {
public:
handle();
handle(char const * name, std::size_t size, unsigned mode = create | open);
handle(handle&& rhs);
~handle();
void swap(handle& rhs);
handle& operator=(handle rhs);
bool valid() const noexcept;
std::size_t size () const noexcept;
char const * name () const noexcept;
std::int32_t ref() const noexcept;
void sub_ref() noexcept;
bool acquire(char const * name, std::size_t size, unsigned mode = create | open);
std::int32_t release();
void* get() const;
void attach(id_t);
id_t detach();
private:
class handle_;
handle_* p_;
};
} // namespace shm
} // namespace ipc

BIN
Thirdparty/libipc/lib/ipc.lib vendored Normal file

Binary file not shown.

BIN
Thirdparty/libipc/lib/ipc_o.lib vendored Normal file

Binary file not shown.

BIN
Thirdparty/libipc/lib/ipcd.lib vendored Normal file

Binary file not shown.

BIN
Thirdparty/libipc/lib/ipcd.pdb vendored Normal file

Binary file not shown.

View File

@ -60,6 +60,8 @@ int Application::RunLoop() {
RHI::Get()->StartRender();
mesh_ = new Mesh;
mesh_->SetVertices(vertices, 3, false);
meshRender_ = new MeshRender(mesh_);

View File

@ -23,12 +23,14 @@ INCLUDE_DIRECTORIES(
${Thirdparty}/glm
${Thirdparty}
${Thirdparty}/spdlog/include
${Thirdparty}/libipc/include
)
link_directories(
${Thirdparty}/glfw/lib-vc2022
${Thirdparty}/glew/lib
${Thirdparty}/spdlog/lib
${Thirdparty}/libipc/lib
)
# IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
@ -66,6 +68,8 @@ target_link_libraries(
glfw3
debug spdlogd
optimized spdlog
debug ipcd
optimized ipc
)

103
src/Ipc/Ipc.cpp Normal file
View File

@ -0,0 +1,103 @@
#include "Ipc/Ipc.h"
#include <functional>
#include "Ipc/ReadCallback.h"
std::shared_ptr<Ipc> Ipc::create(const char* reader_name, const char* writer_name) {
struct Creator : public Ipc {
Creator(const char* reader_name, const char* writer_name) : Ipc(reader_name, writer_name) {}
~Creator() override = default;
};
return std::make_shared<Creator>(reader_name, writer_name);
}
Ipc::Ipc(const char* reader_name, const char* writer_name) noexcept
: reader_name_(reader_name)
, writer_name_(writer_name) {
sender_ = std::make_unique<ipc::channel>(reader_name_.c_str(), ipc::sender);
printf("%s, %s", reader_name, writer_name);
}
Ipc::~Ipc() {
stop();
}
bool Ipc::listen() {
if (reciver_stop_.load(std::memory_order_acquire)) {
return false;
}
reciver_stop_.store(false);
std::weak_ptr<Ipc> wThis = shared_from_this();
reciver_thread_ = std::move(std::thread(std::bind(&Ipc::doReciver, this, wThis)));
return true;
}
void Ipc::stop() {
if (!reciver_stop_.load(std::memory_order_acquire)) {
return;
}
reciver_stop_.store(true, std::memory_order_release);
sender_->disconnect();
receiver_->disconnect();
if (reciver_thread_.joinable()) {
reciver_thread_.join();
}
}
bool Ipc::send(const char* data, unsigned int size) {
if (!sender_) {
return false;
}
return sender_->send(data, size);
}
void Ipc::registReadCallback(const std::shared_ptr<IReaderCallback>& reader) {
std::lock_guard<std::mutex> lock(mutex_);
auto itor = std::find(reader_callbacks_.begin(), reader_callbacks_.end(), reader);
if (reader_callbacks_.end() != itor) {
return;
}
reader_callbacks_.emplace_back(reader);
}
void Ipc::unregistReadCallback(const std::shared_ptr<IReaderCallback>& reader) {
std::lock_guard<std::mutex> lock(mutex_);
auto itor = std::find(reader_callbacks_.begin(), reader_callbacks_.end(), reader);
if (reader_callbacks_.end() != itor) {
return;
}
reader_callbacks_.erase(itor);
}
void Ipc::doReciver(std::weak_ptr<Ipc> wThis) {
std::shared_ptr<Ipc> self(wThis.lock());
if (!self) {
return;
}
receiver_ = std::make_unique<ipc::channel>(writer_name_.c_str(), ipc::receiver);
while (!reciver_stop_.load(std::memory_order_acquire)) {
ipc::buff_t buffer = receiver_->recv();
if (buffer.empty()) {
break;
}
const char* data = buffer.get<const char*>();
onReciveer(data, static_cast<unsigned int>(buffer.size()));
}
}
void Ipc::onReciveer(const char* buffer, unsigned int size) {
std::lock_guard<std::mutex> lock(mutex_);
for (auto& read : reader_callbacks_) {
read->onRead(buffer, size);
}
}

46
src/Ipc/Ipc.h Normal file
View File

@ -0,0 +1,46 @@
#pragma once
#include <thread>
#include <memory>
#include <atomic>
#include <string>
#include <mutex>
#include <libipc/ipc.h>
class IReaderCallback;
class Ipc : public std::enable_shared_from_this<Ipc>{
public:
static std::shared_ptr<Ipc> create(const char* reader_name, const char* writer_name);
public:
virtual ~Ipc();
bool listen();
void stop();
bool send(const char* data, unsigned int size);
void registReadCallback(const std::shared_ptr<IReaderCallback>& reader);
void unregistReadCallback(const std::shared_ptr<IReaderCallback>& reader);
protected:
Ipc(const char* reader_name, const char* writer_name) noexcept;
private:
void doReciver(std::weak_ptr<Ipc> wThis);
void onReciveer(const char* buffer, unsigned int size);
private:
std::string reader_name_;
std::string writer_name_;
std::unique_ptr<ipc::channel> sender_;
std::unique_ptr<ipc::channel> receiver_;
std::thread reciver_thread_;
std::atomic_bool reciver_stop_{false};
std::mutex mutex_;
using ReaderCallbackList = std::vector<std::shared_ptr<IReaderCallback>>;
ReaderCallbackList reader_callbacks_;
};

28
src/Ipc/IpcMoudle.cpp Normal file
View File

@ -0,0 +1,28 @@
#include "Ipc/IpcMoudle.h"
#include "Core/Core.h"
#include "Ipc/ipclib.h"
IpcMoudle* Singleton<IpcMoudle>::instance_ = nullptr;
bool IpcMoudle::Initialize() {
if (!initialize("ipc_sender", "ipc_sender")) {
ERRORLOG("ipc initialize failed");
return false;
}
setReaderCallback([](const char* data, unsigned int size) {
INFOLOG("ipc recive data:{}", size);
}
);
if (!listen()) {
ERRORLOG("ipc listen failed");
return false;
}
return true;
}
void IpcMoudle::Uninitialize() {
uninitialize();
}

15
src/Ipc/IpcMoudle.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include "Core/Singleton.h"
#include "Core/Constant.h"
class IpcMoudle : public Singleton<IpcMoudle> {
NON_COPYABLE(IpcMoudle)
public:
IpcMoudle() = default;
virtual ~IpcMoudle() = default;
bool Initialize() override;
void Uninitialize() override;
};

9
src/Ipc/ReadCallback.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
class IReaderCallback {
public:
virtual ~IReaderCallback() = default;
// read thread callback
virtual void onRead(const char* buffer, unsigned int size) = 0;
};

20
src/Ipc/config.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#ifdef _IPC_EXPORT_
#ifdef WIN32
#define IPC_EXPORT __declspec( dllexport )
#endif // WIN32
#else
#ifdef WIN32
#define IPC_EXPORT __declspec( dllimport )
#endif // WIN32
#endif // _IPC_EXPORT_

69
src/Ipc/ipclib.cpp Normal file
View File

@ -0,0 +1,69 @@
#include "Ipc/ipclib.h"
#include <memory>
#include <assert.h>
#include "Ipc.h"
#include "ReadCallback.h"
class ReaderCallback : public IReaderCallback {
public:
ReaderCallback() = default;
~ReaderCallback() override = default;
void onRead(const char* buffer, unsigned int size) override {
printf("%s", buffer);
if (nullptr != m_readerCallbackFunc) {
m_readerCallbackFunc(buffer, size);
}
}
void setCallback(ReaderCallbackFunc func) {
m_readerCallbackFunc = func;
}
private:
ReaderCallback(const ReaderCallback&) = delete;
ReaderCallback operator= (const ReaderCallback&) = delete;
private:
ReaderCallbackFunc m_readerCallbackFunc{nullptr};
};
std::shared_ptr<Ipc> g_ipc;
std::shared_ptr<ReaderCallback> g_readCallback;
bool __stdcall initialize(const char* sender_name, const char* receiver_name) {
assert(!g_ipc);
g_ipc = Ipc::create(sender_name, receiver_name);
return true;
}
void __stdcall uninitialize() {
assert(g_ipc);
g_ipc->stop();
if (g_readCallback) {
g_ipc->unregistReadCallback(g_readCallback);
g_readCallback.reset();
}
g_ipc.reset();
}
bool __stdcall listen() {
assert(g_ipc);
return g_ipc->listen();
}
bool __stdcall send(const char* data, unsigned int size) {
assert(g_ipc);
return g_ipc->send(data, size);
}
bool __stdcall setReaderCallback(ReaderCallbackFunc callback) {
assert(g_ipc);
if (!g_readCallback) {
g_readCallback = std::make_shared<ReaderCallback>();
g_ipc->registReadCallback(g_readCallback);
}
g_readCallback->setCallback(callback);
return true;
}

21
src/Ipc/ipclib.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include "Ipc/config.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
typedef void(__stdcall *ReaderCallbackFunc)(const char* data, unsigned int size);
IPC_EXPORT bool __stdcall initialize(const char* sender_name, const char* receiver_name);
IPC_EXPORT void __stdcall uninitialize();
IPC_EXPORT bool __stdcall listen();
IPC_EXPORT bool __stdcall send(const char* data, unsigned int size);
IPC_EXPORT bool __stdcall setReaderCallback(ReaderCallbackFunc callback);
#ifdef __cplusplus
}
#endif // __cplusplus

181
src/Main.cpp Normal file
View File

@ -0,0 +1,181 @@
#if 1
#include <Windows.h>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#include <stb/stb_image.h>
#include "Core/Logger.h"
#include "Core/ScopeLock.h"
#include "Ipc/IpcMoudle.h"
#include "shader_s.h"
static int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
Logger::Init();
IpcMoudle::Init();
auto glfwErrorCallback = [](int error, const char* description) {
ERRORLOG("code={}, description={}", error, description);
};
glfwSetErrorCallback(glfwErrorCallback);
if (GLFW_TRUE != glfwInit()) {
return -1; //exit(EXIT_FAILURE);
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_SAMPLES, 4);
if (true) {
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
}
glfwWindowHint(GLFW_RESIZABLE, true);
glfwWindowHint(GLFW_DECORATED, true);
glfwWindowHint(GLFW_FOCUSED, true);
glfwWindowHint(GLFW_MAXIMIZED, false);
glfwWindowHint(GLFW_FLOATING, false);
glfwWindowHint(GLFW_VISIBLE, true);
glfwWindowHint(GLFW_AUTO_ICONIFY, true);
//glfwWindowHint(GLFW_REFRESH_RATE, settings.refreshRate);
glfwWindowHint(GLFW_SAMPLES, 4);
GLFWwindow* window = glfwCreateWindow(860, 540, "humanRender", nullptr, nullptr);
if (!window) {
ERRORLOG("glfwCreateWindow failed");
glfwTerminate();
return false;
}
glfwSetKeyCallback(window, [](GLFWwindow* window, int key, int scancode, int action, int mods) {
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
);
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err) {
const GLubyte* errorString = glewGetErrorString(err);
ERRORLOG("glewInit={1}, err={2}", err, reinterpret_cast<const char*>(errorString));
glfwDestroyWindow(window);
glfwTerminate();
return -1;
}
glfwSwapInterval(1);
float vertices[] = {
// positions // colors // texture coords
1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
unsigned int VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3* sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
// remember: do NOT unbind the EBO while a VAO is active as the bound element buffer object IS stored in the VAO; keep the EBO bound.
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
glBindVertexArray(0);
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture); // all upcoming GL_TEXTURE_2D operations now have effect on this texture object
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
int width, height, nrChannels;
// The FileSystem::getPath(...) is part of the GitHub repository so we can find files on any IDE/platform; replace it with your own image path.
stbi_set_flip_vertically_on_load(true);
unsigned char* data = stbi_load("./data/background/background.jpg", &width, &height, &nrChannels, 0);
if (data) {
if (nrChannels == 3) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
} else if (nrChannels == 4) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
}
glGenerateMipmap(GL_TEXTURE_2D);
} else {
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
Shader shader("./data/shader/texture.vs", "./data/shader/texture.fs");
while (!glfwWindowShouldClose(window)) {
float ratio;
glm::mat4 model, view, projection, mvp;
int width = 0;
int height = 0;
glfwGetFramebufferSize(window, &width, &height);
height = height == 0 ? 1 : height;
ratio = width / (float)height;
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(49.f / 255, 77.f / 255, 121.f / 255, 1.f);
view = glm::lookAt(glm::vec3(0, 0, 10), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
projection = glm::perspective(glm::radians(60.f), ratio, 1.f, 1000.f);
glBindTexture(GL_TEXTURE_2D, texture);
shader.use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
//glDrawArrays(GL_TRIANGLES, 0, 6);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwDestroyWindow(window);
glfwTerminate();
IpcMoudle::Shotdown();
Logger::Shotdown();
return 0;
}
#endif

View File

@ -1,36 +1,36 @@
#if 1
#include <windows.h>
#include "Application/Application.h"
#include "Window/GLFWImpl/GLFWImpl.h"
static int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
Application app;
if (!app.Initialize()) {
return -1;
}
WindowSettings settings;
GLFWImpl impl;
if (!impl.Create(settings)) {
return -1;
}
/*PPEngine::Window::WindowSettings settings;
settings.title = "PPEditor";
PPEngine::PPRHI::DriverSettings driverSettings;
PPEngine::Window::Window window(driverSettings, settings, std::make_unique<CFrameWnd>());*/
//CFrameWnd* window = new CFrameWnd();
//window->Create(NULL, "ProjectorPlayer", WNDSTYLE_FRAME, 0L, 0L, 0, 640, 480);
//window->CenterWindow();
//window->ShowWindow(true);
//godot_hinstance = hInstance;
int ret = app.RunLoop();
app.Uninitialize();
return ret;
}
//#include <windows.h>
//
//#include "Application/Application.h"
//
//#include "Window/GLFWImpl/GLFWImpl.h"
//
//static int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
// Application app;
// if (!app.Initialize()) {
// return -1;
// }
//
// WindowSettings settings;
// GLFWImpl impl;
// if (!impl.Create(settings)) {
// return -1;
// }
//
// /*PPEngine::Window::WindowSettings settings;
// settings.title = "PPEditor";
// PPEngine::PPRHI::DriverSettings driverSettings;
// PPEngine::Window::Window window(driverSettings, settings, std::make_unique<CFrameWnd>());*/
// //CFrameWnd* window = new CFrameWnd();
// //window->Create(NULL, "ProjectorPlayer", WNDSTYLE_FRAME, 0L, 0L, 0, 640, 480);
// //window->CenterWindow();
// //window->ShowWindow(true);
// //godot_hinstance = hInstance;
//
// int ret = app.RunLoop();
// app.Uninitialize();
// return ret;
//}
#else

View File

@ -3,6 +3,7 @@
#include <memory>
#include <vector>
#include "Core/Core.h"
#include "RHI/DriverSettings.h"
#include "RHI/RHICommond.h"
@ -18,43 +19,43 @@ public:
virtual RHICommond* CreateVAOCommand(
class Mesh* mesh,
unsigned int vaoHandle,
unsigned int vboHandle,
unsigned int eboHandle
uint32 vaoHandle,
uint32 vboHandle,
uint32 eboHandle
) = 0;
virtual RHICommond* DrawArrayCommand(
unsigned int vaoHandle,
unsigned int vaoStart,
unsigned int vaoCount
uint32 vaoHandle,
uint32 vaoStart,
uint32 vaoCount
) = 0;
virtual RHICommond* DrawElementsCommand(
unsigned int vaoHandle,
unsigned int eboHandle,
unsigned int eboCount
uint32 vaoHandle,
uint32 eboHandle,
uint32 eboCount
) = 0;
virtual RHICommond* DeleteVAOCommand(
unsigned int vaoHandle,
unsigned int vboHandle,
unsigned int eboHandle
uint32 vaoHandle,
uint32 vboHandle,
uint32 eboHandle
) = 0;
virtual RHICommond* CreateShaderCommand(
unsigned int shaderHandle,
unsigned int type,
uint32 shaderHandle,
uint32 type,
const std::string& shader
) = 0;
virtual RHICommond* DeleteShaderCommand(
unsigned int shaderHandle
uint32 shaderHandle
) = 0;
virtual RHICommond* CreateProgramCommand(
unsigned int programHandle,
const std::vector<unsigned int>& shaders
uint32 programHandle,
const std::vector<uint32>& shaders
) = 0;
virtual RHICommond* UseProgramCommand(
unsigned int programHandle,
uint32 programHandle,
bool use
) = 0;
virtual RHICommond* DeleteProgramCommand(
unsigned int programHandle
uint32 programHandle
) = 0;
virtual RHICommond* CreateStartCommand() = 0;
virtual RHICommond* CreateEndCommand() = 0;

View File

@ -265,11 +265,11 @@ void GLStartCommand::OnExecute() {
GLEndCommand::GLEndCommand()
: RHICommond(RHICommond::Type::END_FRAME) {
//INFOLOG("actor {}", spdlog::fmt_lib::ptr(this));
INFOLOG("actor {}", spdlog::fmt_lib::ptr(this));
}
GLEndCommand::~GLEndCommand() {
//INFOLOG("dctor {}", spdlog::fmt_lib::ptr(this));
INFOLOG("dctor {}", spdlog::fmt_lib::ptr(this));
}
@ -280,3 +280,4 @@ void GLEndCommand::OnExecute() {
}
setting.renderSwapBuffers();
}

View File

@ -1,6 +1,7 @@
#include "Renderer/MeshRender.h"
#include "RHI/OpenglDrv/GLHandleMapper.h"
#include "Renderer/ShaderSoruce.h"
MeshRender::MeshRender(Mesh* mesh)
: mesh_(mesh) {
@ -16,6 +17,8 @@ MeshRender::~MeshRender() {
RHI::Get()->Push(task);
}
uint32 vsHandle = 0;
uint32 fsHandle = 0;
void MeshRender::Render() {
if (nullptr == mesh_) {
return;
@ -27,6 +30,8 @@ void MeshRender::Render() {
eboHandle_ = GLHandleMapper::GeneratorEBOHandle();
auto task = rhiApi_->CreateVAOCommand(mesh_, vaoHandle_, vboHandle_, eboHandle_);
RHI::Get()->Push(task);
vsHandle = GLHandleMapper::GeneratorShaderHandle();
//rhiApi_->CreateShaderCommand()
} else {
auto task = rhiApi_->DrawElementsCommand(vaoHandle_, eboHandle_, mesh_->GetIndexCount());
RHI::Get()->Push(task);

View File

@ -0,0 +1,28 @@
#pragma once
//顶点着色器代码
static const char* vertex_shader_text =
"#version 330\n"
"uniform mat4 u_mvp;\n"
"in vec3 a_pos;\n"
"in vec4 a_color;\n"
"out vec4 v_color;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(a_pos, 1.0);\n"
" v_color = a_color;\n"
"}\n";
//片段着色器代码
static const char* fragment_shader_text =
"#version 330\n"
"in vec4 v_color;\n"
"out vec4 o_fragColor;\n"
"void main()\n"
"{\n"
" o_fragColor = v_color;\n"
"}\n";

123
src/shader_s.h Normal file
View File

@ -0,0 +1,123 @@
#ifndef SHADER_H
#define SHADER_H
#define GLEW_STATIC
#include <GL/glew.h>
#include <glfw/glfw3.h>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
class Shader
{
public:
unsigned int ID;
// constructor generates the shader on the fly
// ------------------------------------------------------------------------
Shader(const char* vertexPath, const char* fragmentPath)
{
// 1. retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// ensure ifstream objects can throw exceptions:
vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
try
{
// open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure& e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;
}
const char* vShaderCode = vertexCode.c_str();
const char * fShaderCode = fragmentCode.c_str();
// 2. compile shaders
unsigned int vertex, fragment;
// vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// shader Program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
// delete the shaders as they're linked into our program now and no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
}
// activate the shader
// ------------------------------------------------------------------------
void use()
{
glUseProgram(ID);
}
// utility uniform functions
// ------------------------------------------------------------------------
void setBool(const std::string &name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
// ------------------------------------------------------------------------
void setInt(const std::string &name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
// ------------------------------------------------------------------------
void setFloat(const std::string &name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
private:
// utility function for checking shader compilation/linking errors.
// ------------------------------------------------------------------------
void checkCompileErrors(unsigned int shader, std::string type)
{
int success;
char infoLog[1024];
if (type != "PROGRAM")
{
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
else
{
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
}
};
#endif