mirror of https://github.com/AxioDL/metaforce.git
WIP Metal backend for VISIGen
This commit is contained in:
parent
55438bd2ea
commit
42dba1148d
|
@ -7,7 +7,6 @@ if (NOT MSVC)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
add_executable(visigen
|
add_executable(visigen
|
||||||
VISIBuilder.cpp
|
VISIBuilder.cpp
|
||||||
VISIBuilder.hpp
|
VISIBuilder.hpp
|
||||||
|
@ -29,17 +28,21 @@ else()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
target_sources(visigen PRIVATE MainMac.mm)
|
target_sources(visigen PRIVATE MainMac.mm VISIRendererMetal.mm VISIRendererMetal.hh)
|
||||||
set_source_files_properties(MainMac.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
set_source_files_properties(MainMac.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||||
|
set_source_files_properties(VISIRendererMetal.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
|
||||||
|
find_library(METAL_LIBRARY Metal REQUIRED)
|
||||||
|
target_link_libraries(visigen PRIVATE ${METAL_LIBRARY})
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
target_sources(visigen PRIVATE MainWin.cpp)
|
target_sources(visigen PRIVATE
|
||||||
|
MainWin.cpp
|
||||||
|
VISIRendererOpenGL.cpp
|
||||||
|
VISIRendererOpenGL.hpp)
|
||||||
else()
|
else()
|
||||||
target_sources(visigen PRIVATE MainXlib.cpp)
|
target_sources(visigen PRIVATE
|
||||||
endif()
|
MainXlib.cpp
|
||||||
|
VISIRendererOpenGL.cpp
|
||||||
if(APPLE)
|
VISIRendererOpenGL.hpp)
|
||||||
find_library(OPENGL_LIBRARY OpenGL)
|
|
||||||
target_link_libraries(visigen PRIVATE ${OPENGL_LIBRARY})
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(visigen PRIVATE
|
target_link_libraries(visigen PRIVATE
|
||||||
|
@ -50,6 +53,8 @@ target_link_libraries(visigen PRIVATE
|
||||||
lzokay
|
lzokay
|
||||||
xxhash
|
xxhash
|
||||||
zeus
|
zeus
|
||||||
|
png
|
||||||
${ZLIB_LIBRARIES}
|
${ZLIB_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
target_include_directories(visigen PRIVATE ${PNG_INCLUDE_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,119 +1,23 @@
|
||||||
#include "VISIRenderer.hpp"
|
#include "../version.h"
|
||||||
#include <AppKit/AppKit.h>
|
#include "VISIRendererMetal.hh"
|
||||||
#include "athena/Global.hpp"
|
#include "athena/Global.hpp"
|
||||||
#include "logvisor/logvisor.hpp"
|
#include "logvisor/logvisor.hpp"
|
||||||
#include "../version.h"
|
#include <AppKit/AppKit.h>
|
||||||
|
#include <MetalKit/MetalKit.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#if !__has_feature(objc_arc)
|
#if !__has_feature(objc_arc)
|
||||||
#error ARC Required
|
#error ARC Required
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static std::thread s_task;
|
|
||||||
|
|
||||||
static const NSOpenGLPixelFormatAttribute PF_RGBA8_Z24_ATTRS[] =
|
|
||||||
{
|
|
||||||
NSOpenGLPFAAccelerated,
|
|
||||||
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
|
|
||||||
//NSOpenGLPFADoubleBuffer,
|
|
||||||
NSOpenGLPFAColorSize, 24,
|
|
||||||
NSOpenGLPFAAlphaSize, 8,
|
|
||||||
NSOpenGLPFADepthSize, 24,
|
|
||||||
0, 0
|
|
||||||
};
|
|
||||||
|
|
||||||
@interface OpenGLView : NSOpenGLView
|
|
||||||
{
|
|
||||||
VISIRenderer* m_renderer;
|
|
||||||
}
|
|
||||||
- (id)initWithFrame:(NSRect)frame renderer:(VISIRenderer*)renderer;
|
|
||||||
@end
|
|
||||||
|
|
||||||
static NSWindow* s_Window;
|
|
||||||
static void UpdatePercent(float percent)
|
|
||||||
{
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
s_Window.title = [NSString stringWithFormat:@"VISIGen [%g%%]", percent * 100.f];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@implementation OpenGLView
|
|
||||||
- (id)initWithFrame:(NSRect)frame renderer:(VISIRenderer*)renderer;
|
|
||||||
{
|
|
||||||
NSOpenGLPixelFormat* pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:PF_RGBA8_Z24_ATTRS];
|
|
||||||
self = [super initWithFrame:frame pixelFormat:pf];
|
|
||||||
m_renderer = renderer;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
- (void)prepareOpenGL
|
|
||||||
{
|
|
||||||
[super prepareOpenGL];
|
|
||||||
s_task = std::thread([self](){
|
|
||||||
[[self openGLContext] makeCurrentContext];
|
|
||||||
m_renderer->Run(UpdatePercent);
|
|
||||||
[NSApp terminate:nil];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
|
||||||
{
|
|
||||||
VISIRenderer* m_renderer;
|
|
||||||
NSWindow* m_window;
|
|
||||||
NSOpenGLView* m_glView;
|
|
||||||
int m_instanceIdx;
|
|
||||||
}
|
|
||||||
- (id)initWithRenderer:(VISIRenderer*)renderer instIdx:(int)instIdx;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation AppDelegate
|
|
||||||
- (id)initWithRenderer:(VISIRenderer*)renderer instIdx:(int)instIdx
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
m_renderer = renderer;
|
|
||||||
m_instanceIdx = instIdx;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
- (void)applicationDidFinishLaunching:(NSNotification*)notification
|
|
||||||
{
|
|
||||||
int x = 0;
|
|
||||||
int y = 0;
|
|
||||||
if (m_instanceIdx != -1)
|
|
||||||
{
|
|
||||||
x = (m_instanceIdx & 1) != 0;
|
|
||||||
y = (m_instanceIdx & 2) != 0;
|
|
||||||
}
|
|
||||||
NSRect cRect = NSMakeRect(x * 768, y * 534, 768, 512);
|
|
||||||
m_window = [[NSWindow alloc] initWithContentRect:cRect
|
|
||||||
styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable
|
|
||||||
backing:NSBackingStoreBuffered
|
|
||||||
defer:NO];
|
|
||||||
m_window.releasedWhenClosed = NO;
|
|
||||||
m_window.title = @"VISIGen";
|
|
||||||
s_Window = m_window;
|
|
||||||
m_glView = [[OpenGLView alloc] initWithFrame:cRect renderer:m_renderer];
|
|
||||||
m_window.contentView = m_glView;
|
|
||||||
[m_window makeKeyAndOrderFront:nil];
|
|
||||||
}
|
|
||||||
- (void)applicationWillTerminate:(NSNotification*)notification
|
|
||||||
{
|
|
||||||
m_renderer->Terminate();
|
|
||||||
if (s_task.joinable())
|
|
||||||
s_task.join();
|
|
||||||
exit(m_renderer->ReturnVal());
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
static logvisor::Module AthenaLog("Athena");
|
static logvisor::Module AthenaLog("Athena");
|
||||||
static void AthenaExc(athena::error::Level level, const char * /*file*/, const char *, int /*line*/,
|
static void AthenaExc(athena::error::Level level, const char * /*file*/, const char *, int /*line*/,
|
||||||
fmt::string_view fmt, fmt::format_args args) {
|
fmt::string_view fmt, fmt::format_args args) {
|
||||||
AthenaLog.vreport(logvisor::Level(level), fmt, args);
|
AthenaLog.vreport(logvisor::Level(level), fmt, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char** argv)
|
int main(int argc, const char **argv) {
|
||||||
{
|
if (argc > 1 && !strcmp(argv[1], "--dlpackage")) {
|
||||||
if (argc > 1 && !strcmp(argv[1], "--dlpackage"))
|
|
||||||
{
|
|
||||||
fmt::print(FMT_STRING("{}\n"), METAFORCE_DLPACKAGE);
|
fmt::print(FMT_STRING("{}\n"), METAFORCE_DLPACKAGE);
|
||||||
return 100;
|
return 100;
|
||||||
}
|
}
|
||||||
|
@ -121,18 +25,9 @@ int main(int argc, const char** argv)
|
||||||
logvisor::RegisterStandardExceptions();
|
logvisor::RegisterStandardExceptions();
|
||||||
logvisor::RegisterConsoleLogger();
|
logvisor::RegisterConsoleLogger();
|
||||||
atSetExceptionHandler(AthenaExc);
|
atSetExceptionHandler(AthenaExc);
|
||||||
VISIRenderer renderer(argc, argv);
|
VISIRendererMetal renderer(argc, argv);
|
||||||
int instIdx = -1;
|
@autoreleasepool {
|
||||||
if (argc > 3)
|
renderer.Run(nullptr);
|
||||||
instIdx = atoi(argv[3]);
|
|
||||||
@autoreleasepool
|
|
||||||
{
|
|
||||||
[[NSApplication sharedApplication] setActivationPolicy:NSApplicationActivationPolicyRegular];
|
|
||||||
|
|
||||||
/* Delegate (OS X callbacks) */
|
|
||||||
AppDelegate* appDelegate = [[AppDelegate alloc] initWithRenderer:&renderer instIdx:instIdx];
|
|
||||||
[[NSApplication sharedApplication] setDelegate:appDelegate];
|
|
||||||
[[NSApplication sharedApplication] run];
|
|
||||||
}
|
}
|
||||||
return renderer.ReturnVal();
|
return renderer.ReturnVal();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "VISIRenderer.hpp"
|
#include "VISIRendererOpenGL.hpp"
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <WinUser.h>
|
#include <WinUser.h>
|
||||||
#include <Shlwapi.h>
|
#include <Shlwapi.h>
|
||||||
|
@ -49,7 +49,7 @@ int wmain(int argc, const hecl::SystemChar** argv) {
|
||||||
logvisor::RegisterStandardExceptions();
|
logvisor::RegisterStandardExceptions();
|
||||||
logvisor::RegisterConsoleLogger();
|
logvisor::RegisterConsoleLogger();
|
||||||
atSetExceptionHandler(AthenaExc);
|
atSetExceptionHandler(AthenaExc);
|
||||||
VISIRenderer renderer(argc, argv);
|
VISIRendererOpenGL renderer(argc, argv);
|
||||||
s_Renderer = &renderer;
|
s_Renderer = &renderer;
|
||||||
|
|
||||||
int instIdx = -1;
|
int instIdx = -1;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "VISIRenderer.hpp"
|
#include "VISIRendererOpenGL.hpp"
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
#include <GL/glx.h>
|
#include <GL/glx.h>
|
||||||
|
@ -86,7 +86,7 @@ int main(int argc, const char** argv) {
|
||||||
logvisor::RegisterStandardExceptions();
|
logvisor::RegisterStandardExceptions();
|
||||||
logvisor::RegisterConsoleLogger();
|
logvisor::RegisterConsoleLogger();
|
||||||
atSetExceptionHandler(AthenaExc);
|
atSetExceptionHandler(AthenaExc);
|
||||||
VISIRenderer renderer(argc, argv);
|
VISIRendererOpenGL renderer(argc, argv);
|
||||||
|
|
||||||
if (!XInitThreads()) {
|
if (!XInitThreads()) {
|
||||||
Log.report(logvisor::Error, FMT_STRING("X doesn't support multithreading"));
|
Log.report(logvisor::Error, FMT_STRING("X doesn't support multithreading"));
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
#include "ShaderTypes.h"
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
/*static const matrix_float4x4 LookMATs[] = {
|
||||||
|
{// Forward
|
||||||
|
{1.f, 0.f, 0.f, 0.f},
|
||||||
|
{0.f, 0.f, 1.f, 0.f},
|
||||||
|
{0.f, -1.f, 0.f, 0.f},
|
||||||
|
{0.f, 0.f, 0.f, 1.f}},
|
||||||
|
{// Backward
|
||||||
|
{-1.f, 0.f, 0.f, 0.f},
|
||||||
|
{0.f, 0.f, 1.f, 0.f},
|
||||||
|
{0.f, 1.f, 0.f, 0.f},
|
||||||
|
{0.f, 0.f, 0.f, 1.f}},
|
||||||
|
{// Up
|
||||||
|
{1.f, 0.f, 0.f, 0.f},
|
||||||
|
{0.f, -1.f, 0.f, 0.f},
|
||||||
|
{0.f, 0.f, -1.f, 0.f},
|
||||||
|
{0.f, 0.f, 0.f, 1.f}},
|
||||||
|
{// Down
|
||||||
|
{1.f, 0.f, 0.f, 0.f},
|
||||||
|
{0.f, 1.f, 0.f, 0.f},
|
||||||
|
{0.f, 0.f, 1.f, 0.f},
|
||||||
|
{0.f, 0.f, 0.f, 1.f}},
|
||||||
|
{// Left
|
||||||
|
{0.f, 1.f, 0.f, 0.f},
|
||||||
|
{0.f, 0.f, 1.f, 0.f},
|
||||||
|
{1.f, 0.f, 0.f, 0.f},
|
||||||
|
{0.f, 0.f, 0.f, 1.f}},
|
||||||
|
{// Right
|
||||||
|
{0.f, -1.f, 0.f, 0.f},
|
||||||
|
{0.f, 0.f, 1.f, 0.f},
|
||||||
|
{-1.f, 0.f, 0.f, 0.f},
|
||||||
|
{0.f, 0.f, 0.f, 1.f}},
|
||||||
|
};*/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
float4 position [[position]];
|
||||||
|
float4 color;
|
||||||
|
} ColorInOut;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
float3 position [[attribute(VertexAttributePosition)]];
|
||||||
|
float4 color [[attribute(VertexAttributeColor)]];
|
||||||
|
} Vertex;
|
||||||
|
|
||||||
|
vertex ColorInOut vertexShader(Vertex in [[stage_in]], constant Uniforms& uniforms [[buffer(BufferIndexUniforms)]])
|
||||||
|
{
|
||||||
|
ColorInOut out;
|
||||||
|
|
||||||
|
float4 position = float4(in.position, 1.0);
|
||||||
|
position.y *= -1.f;
|
||||||
|
out.position = uniforms.projectionMatrix * uniforms.modelViewMatrix * position;
|
||||||
|
out.color = in.color;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 fragmentShader(ColorInOut in [[stage_in]])
|
||||||
|
{
|
||||||
|
return in.color;
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef ShaderTypes_h
|
||||||
|
#define ShaderTypes_h
|
||||||
|
|
||||||
|
#ifdef __METAL_VERSION__
|
||||||
|
#define NS_ENUM(_type, _name) \
|
||||||
|
enum _name : _type _name; \
|
||||||
|
enum _name : _type
|
||||||
|
#define NSInteger metal::int32_t
|
||||||
|
#else
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
typedef NS_ENUM(NSInteger, BufferIndex) {
|
||||||
|
BufferIndexVertex = 0,
|
||||||
|
BufferIndexUniforms = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef NS_ENUM(NSInteger, VertexAttribute) {
|
||||||
|
VertexAttributePosition = 0,
|
||||||
|
VertexAttributeColor = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Uniforms {
|
||||||
|
matrix_float4x4 projectionMatrix;
|
||||||
|
matrix_float4x4 modelViewMatrix;
|
||||||
|
} Uniforms;
|
||||||
|
|
||||||
|
#endif /* ShaderTypes_h */
|
|
@ -1,6 +1,9 @@
|
||||||
#include "VISIBuilder.hpp"
|
#include "VISIBuilder.hpp"
|
||||||
#include "logvisor/logvisor.hpp"
|
#include "logvisor/logvisor.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
@ -15,16 +18,29 @@ VISIBuilder::PVSRenderCache::PVSRenderCache(VISIRenderer& renderer) : m_renderer
|
||||||
|
|
||||||
static std::unique_ptr<VISIRenderer::RGBA8[]> RGBABuf(new VISIRenderer::RGBA8[256 * 256 * 6]);
|
static std::unique_ptr<VISIRenderer::RGBA8[]> RGBABuf(new VISIRenderer::RGBA8[256 * 256 * 6]);
|
||||||
|
|
||||||
|
size_t VISIBuilder::m_frame = 0;
|
||||||
|
|
||||||
const VISIBuilder::Leaf& VISIBuilder::PVSRenderCache::GetLeaf(const zeus::CVector3f& vec) {
|
const VISIBuilder::Leaf& VISIBuilder::PVSRenderCache::GetLeaf(const zeus::CVector3f& vec) {
|
||||||
auto search = m_cache.find(vec);
|
auto search = m_cache.find(vec);
|
||||||
if (search != m_cache.cend()) {
|
if (search != m_cache.cend()) {
|
||||||
// Log.report(logvisor::Info, FMT_STRING("Cache hit"));
|
|
||||||
return *search->second;
|
return *search->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log.report(logvisor::Info, FMT_STRING("Rendering"));
|
m_renderer.SetupRenderPass(vec);
|
||||||
|
|
||||||
bool needsTransparent = false;
|
bool needsTransparent = false;
|
||||||
m_renderer.RenderPVSOpaque(RGBABuf.get(), vec, needsTransparent);
|
m_renderer.RenderPVSOpaque(RGBABuf.get(), needsTransparent);
|
||||||
|
|
||||||
|
// size_t outsize;
|
||||||
|
// auto* buf = VISIRenderer::makePNGBuffer(reinterpret_cast<unsigned char*>(RGBABuf.get()), 768, 512, &outsize);
|
||||||
|
// auto filename = fmt::format(FMT_STRING("outx{}.png"), m_frame++);
|
||||||
|
// std::cout << "Rendering " << filename << std::endl;
|
||||||
|
// std::ofstream fout;
|
||||||
|
// fout.open(filename, std::ios::binary | std::ios::out);
|
||||||
|
// fout.write(static_cast<const char*>(buf), outsize);
|
||||||
|
// fout.close();
|
||||||
|
// free(buf);
|
||||||
|
|
||||||
std::unique_ptr<Leaf> leafOut = std::make_unique<Leaf>();
|
std::unique_ptr<Leaf> leafOut = std::make_unique<Leaf>();
|
||||||
for (unsigned i = 0; i < 768 * 512; ++i) {
|
for (unsigned i = 0; i < 768 * 512; ++i) {
|
||||||
const VISIRenderer::RGBA8& pixel = RGBABuf[i];
|
const VISIRenderer::RGBA8& pixel = RGBABuf[i];
|
||||||
|
@ -39,18 +55,20 @@ const VISIBuilder::Leaf& VISIBuilder::PVSRenderCache::GetLeaf(const zeus::CVecto
|
||||||
leafOut->setLightEnum(m_lightMetaBit + idx * 2, state);
|
leafOut->setLightEnum(m_lightMetaBit + idx * 2, state);
|
||||||
};
|
};
|
||||||
if (needsTransparent)
|
if (needsTransparent)
|
||||||
m_renderer.RenderPVSTransparent(setBitLambda, vec);
|
m_renderer.RenderPVSTransparent(setBitLambda);
|
||||||
m_renderer.RenderPVSEntitiesAndLights(setBitLambda, setLightLambda, vec);
|
m_renderer.RenderPVSEntitiesAndLights(setBitLambda, setLightLambda);
|
||||||
|
|
||||||
return *m_cache.emplace(std::make_pair(vec, std::move(leafOut))).first->second;
|
return *m_cache.emplace(std::make_pair(vec, std::move(leafOut))).first->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VISIBuilder::Progress::report(int divisions) {
|
void VISIBuilder::Progress::report(int divisions) {
|
||||||
m_prog += 1.f / divisions;
|
m_prog += 1.f / divisions;
|
||||||
// printf(" %g%% \r", m_prog * 100.f);
|
if (m_updatePercent != nullptr) {
|
||||||
// fflush(stdout);
|
|
||||||
if (m_updatePercent)
|
|
||||||
m_updatePercent(m_prog);
|
m_updatePercent(m_prog);
|
||||||
|
} else {
|
||||||
|
printf(" %g%% \r", m_prog * 100.f);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VISIBuilder::Node::buildChildren(int level, int divisions, const zeus::CAABox& curAabb, PVSRenderCache& rc,
|
void VISIBuilder::Node::buildChildren(int level, int divisions, const zeus::CAABox& curAabb, PVSRenderCache& rc,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "VISIRenderer.hpp"
|
#include "VISIRenderer.hpp"
|
||||||
#include "zeus/CAABox.hpp"
|
|
||||||
#include "xxhash/xxhash.h"
|
|
||||||
#include "athena/MemoryWriter.hpp"
|
#include "athena/MemoryWriter.hpp"
|
||||||
|
#include "xxhash/xxhash.h"
|
||||||
|
#include "zeus/CAABox.hpp"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -23,6 +23,8 @@ struct hash<zeus::CVector3f> {
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
||||||
struct VISIBuilder {
|
struct VISIBuilder {
|
||||||
|
static size_t m_frame;
|
||||||
|
|
||||||
struct Leaf {
|
struct Leaf {
|
||||||
std::vector<uint8_t> bits;
|
std::vector<uint8_t> bits;
|
||||||
void setBit(size_t bit) {
|
void setBit(size_t bit) {
|
||||||
|
|
|
@ -1,112 +1,144 @@
|
||||||
#include "VISIRenderer.hpp"
|
#include "VISIRenderer.hpp"
|
||||||
#include "athena/FileReader.hpp"
|
|
||||||
#include "zeus/CAABox.hpp"
|
|
||||||
#include "VISIBuilder.hpp"
|
#include "VISIBuilder.hpp"
|
||||||
#include "zeus/CFrustum.hpp"
|
#include "athena/FileReader.hpp"
|
||||||
#include "logvisor/logvisor.hpp"
|
#include "logvisor/logvisor.hpp"
|
||||||
|
|
||||||
|
#include <png.h>
|
||||||
|
|
||||||
static logvisor::Module Log("visigen");
|
static logvisor::Module Log("visigen");
|
||||||
|
|
||||||
static const char* VS =
|
/* structure to store PNG image bytes */
|
||||||
"#version 330\n"
|
struct mem_encode
|
||||||
"layout(location=0) in vec4 posIn;\n"
|
{
|
||||||
"layout(location=1) in vec4 colorIn;\n"
|
char *buffer;
|
||||||
"\n"
|
size_t size;
|
||||||
"uniform UniformBlock\n"
|
};
|
||||||
"{\n"
|
|
||||||
" mat4 xf;\n"
|
|
||||||
"};\n"
|
|
||||||
"\n"
|
|
||||||
"struct VertToFrag\n"
|
|
||||||
"{\n"
|
|
||||||
" vec4 color;\n"
|
|
||||||
"};\n"
|
|
||||||
"\n"
|
|
||||||
"out VertToFrag vtf;\n"
|
|
||||||
"void main()\n"
|
|
||||||
"{\n"
|
|
||||||
" vtf.color = colorIn;\n"
|
|
||||||
" gl_Position = xf * vec4(posIn.xyz, 1.0);\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
static const char* FS =
|
static void
|
||||||
"#version 330\n"
|
my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||||
"struct VertToFrag\n"
|
{
|
||||||
"{\n"
|
/* with libpng15 next line causes pointer deference error; use libpng12 */
|
||||||
" vec4 color;\n"
|
struct mem_encode* p=(struct mem_encode*)png_get_io_ptr(png_ptr); /* was png_ptr->io_ptr */
|
||||||
"};\n"
|
size_t nsize = p->size + length;
|
||||||
"\n"
|
|
||||||
"in VertToFrag vtf;\n"
|
|
||||||
"layout(location=0) out vec4 colorOut;\n"
|
|
||||||
"void main()\n"
|
|
||||||
"{\n"
|
|
||||||
" colorOut = vtf.color;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
static const uint32_t AABBIdxs[20] = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 1, 7, 3, 5, 5, 0, 0, 2, 6, 4};
|
/* allocate or grow buffer */
|
||||||
|
if(p->buffer)
|
||||||
|
p->buffer = (char *) realloc(p->buffer, nsize);
|
||||||
|
else
|
||||||
|
p->buffer = (char *) malloc(nsize);
|
||||||
|
|
||||||
bool VISIRenderer::SetupShaders() {
|
if(!p->buffer)
|
||||||
m_vtxShader = glCreateShader(GL_VERTEX_SHADER);
|
png_error(png_ptr, "Write Error");
|
||||||
m_fragShader = glCreateShader(GL_FRAGMENT_SHADER);
|
|
||||||
m_program = glCreateProgram();
|
|
||||||
|
|
||||||
glShaderSource(m_vtxShader, 1, &VS, nullptr);
|
/* copy new bytes to end of buffer */
|
||||||
glCompileShader(m_vtxShader);
|
memcpy(p->buffer + p->size, data, length);
|
||||||
GLint status;
|
p->size += length;
|
||||||
glGetShaderiv(m_vtxShader, GL_COMPILE_STATUS, &status);
|
|
||||||
if (status != GL_TRUE) {
|
|
||||||
GLint logLen;
|
|
||||||
glGetShaderiv(m_vtxShader, GL_INFO_LOG_LENGTH, &logLen);
|
|
||||||
char* log = (char*)malloc(logLen);
|
|
||||||
glGetShaderInfoLog(m_vtxShader, logLen, nullptr, log);
|
|
||||||
Log.report(logvisor::Error, FMT_STRING("unable to compile vert source\n{}\n{}\n"), log, VS);
|
|
||||||
free(log);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glShaderSource(m_fragShader, 1, &FS, nullptr);
|
/*
|
||||||
glCompileShader(m_fragShader);
|
write an rgba image to a memory buffer in PNG format, without any fanciness.
|
||||||
glGetShaderiv(m_fragShader, GL_COMPILE_STATUS, &status);
|
|
||||||
if (status != GL_TRUE) {
|
Params: rgba - the rgba values
|
||||||
GLint logLen;
|
width - image width
|
||||||
glGetShaderiv(m_fragShader, GL_INFO_LOG_LENGTH, &logLen);
|
height - image height
|
||||||
char* log = (char*)malloc(logLen);
|
outsize - return for size of output buffer
|
||||||
glGetShaderInfoLog(m_fragShader, logLen, nullptr, log);
|
Returns: pointer to allocated buffer holding png data
|
||||||
Log.report(logvisor::Error, FMT_STRING("unable to compile frag source\n{}\n{}\n"), log, FS);
|
*/
|
||||||
free(log);
|
void *VISIRenderer::makePNGBuffer(unsigned char *rgba, int width, int height, size_t *outsize)
|
||||||
return false;
|
{
|
||||||
|
int code = 0;
|
||||||
|
// FILE *fp;
|
||||||
|
png_structp png_ptr = 0;
|
||||||
|
png_infop info_ptr =0;
|
||||||
|
png_bytep row = 0;
|
||||||
|
|
||||||
|
struct mem_encode state = {0, 0};
|
||||||
|
|
||||||
|
*outsize = 0;
|
||||||
|
|
||||||
|
// Initialize write structure
|
||||||
|
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
if (png_ptr == NULL) {
|
||||||
|
fprintf(stderr, "Could not allocate write struct\n");
|
||||||
|
code = 1;
|
||||||
|
goto finalise;
|
||||||
}
|
}
|
||||||
|
|
||||||
glAttachShader(m_program, m_vtxShader);
|
// Initialize info structure
|
||||||
glAttachShader(m_program, m_fragShader);
|
info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
if (info_ptr == NULL) {
|
||||||
glLinkProgram(m_program);
|
fprintf(stderr, "Could not allocate info struct\n");
|
||||||
glGetProgramiv(m_program, GL_LINK_STATUS, &status);
|
code = 1;
|
||||||
if (status != GL_TRUE) {
|
goto finalise;
|
||||||
GLint logLen;
|
|
||||||
glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &logLen);
|
|
||||||
char* log = (char*)malloc(logLen);
|
|
||||||
glGetProgramInfoLog(m_program, logLen, nullptr, log);
|
|
||||||
Log.report(logvisor::Error, FMT_STRING("unable to link shader program\n{}\n"), log);
|
|
||||||
free(log);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glUseProgram(m_program);
|
// Setup Exception handling
|
||||||
m_uniLoc = glGetUniformBlockIndex(m_program, "UniformBlock");
|
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||||
|
fprintf(stderr, "Error during png creation\n");
|
||||||
|
code = 1;
|
||||||
|
goto finalise;
|
||||||
|
}
|
||||||
|
|
||||||
glGenBuffers(1, &m_uniformBufferGL);
|
// png_init_io(png_ptr, fp);
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, m_uniformBufferGL);
|
|
||||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformBuffer), nullptr, GL_DYNAMIC_DRAW);
|
|
||||||
|
|
||||||
glGenBuffers(1, &m_aabbIBO);
|
/* if my_png_flush() is not needed, change the arg to NULL */
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_aabbIBO);
|
png_set_write_fn(png_ptr, &state, my_png_write_data, NULL);
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 20 * 4, AABBIdxs, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
glEnable(GL_PRIMITIVE_RESTART);
|
// Write header (8 bit colour depth)
|
||||||
glPrimitiveRestartIndex(0xffffffff);
|
png_set_IHDR(png_ptr, info_ptr, width, height,
|
||||||
|
8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
|
||||||
|
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||||
|
|
||||||
return true;
|
// Set title
|
||||||
|
/*
|
||||||
|
if (title != NULL) {
|
||||||
|
png_text title_text;
|
||||||
|
title_text.compression = PNG_TEXT_COMPRESSION_NONE;
|
||||||
|
title_text.key = "Title";
|
||||||
|
title_text.text = title;
|
||||||
|
png_set_text(png_ptr, info_ptr, &title_text, 1);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
png_write_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
// Allocate memory for one row (4 bytes per pixel - RGBA)
|
||||||
|
row = (png_bytep) malloc(4 * width * sizeof(png_byte));
|
||||||
|
|
||||||
|
// Write image data
|
||||||
|
int x, y;
|
||||||
|
for (y=0 ; y<height ; y++) {
|
||||||
|
for (x=0 ; x<width ; x++) {
|
||||||
|
// setRGB(&(row[x*3]), buffer[y*width + x]);
|
||||||
|
row[x*4] = rgba[(y*width +x)*4];
|
||||||
|
row[x*4+1] = rgba[(y*width +x)*4+1];
|
||||||
|
row[x*4+2] = rgba[(y*width +x)*4+2];
|
||||||
|
row[x*4+3] = rgba[(y*width +x)*4+3];
|
||||||
|
// row[x*4] = 255;
|
||||||
|
// row[x*4+1] = 0;
|
||||||
|
// row[x*4+2] = 255;
|
||||||
|
// row[x*4+3] = 255;
|
||||||
|
}
|
||||||
|
png_write_row(png_ptr, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
// End write
|
||||||
|
png_write_end(png_ptr, NULL);
|
||||||
|
|
||||||
|
finalise:
|
||||||
|
// if (fp != NULL) fclose(fp);
|
||||||
|
if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
|
||||||
|
if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
|
||||||
|
if (row != NULL) free(row);
|
||||||
|
|
||||||
|
*outsize = state.size;
|
||||||
|
return state.buffer;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
zeus::CColor VISIRenderer::ColorForIndex(uint32_t i) {
|
||||||
|
i += 1;
|
||||||
|
return zeus::CColor((i & 0xff) / 255.f, ((i >> 8) & 0xff) / 255.f, ((i >> 16) & 0xff) / 255.f, 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<VISIRenderer::Model::Vert> VISIRenderer::AABBToVerts(const zeus::CAABox& aabb, const zeus::CColor& color) {
|
std::vector<VISIRenderer::Model::Vert> VISIRenderer::AABBToVerts(const zeus::CAABox& aabb, const zeus::CColor& color) {
|
||||||
|
@ -128,302 +160,8 @@ std::vector<VISIRenderer::Model::Vert> VISIRenderer::AABBToVerts(const zeus::CAA
|
||||||
return verts;
|
return verts;
|
||||||
}
|
}
|
||||||
|
|
||||||
static zeus::CColor ColorForIndex(int i) {
|
|
||||||
i += 1;
|
|
||||||
return zeus::CColor((i & 0xff) / 255.f, ((i >> 8) & 0xff) / 255.f, ((i >> 16) & 0xff) / 255.f, 1.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VISIRenderer::SetupVertexBuffersAndFormats() {
|
|
||||||
for (Model& model : m_models) {
|
|
||||||
glGenVertexArrays(1, &model.vao);
|
|
||||||
glGenBuffers(1, &model.vbo);
|
|
||||||
glGenBuffers(1, &model.ibo);
|
|
||||||
|
|
||||||
glBindVertexArray(model.vao);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, model.vbo);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, model.verts.size() * sizeof(Model::Vert), model.verts.data(), GL_STATIC_DRAW);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glEnableVertexAttribArray(1);
|
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(Model::Vert), 0);
|
|
||||||
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Model::Vert), (void*)16);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model.ibo);
|
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, model.idxs.size() * 4, model.idxs.data(), GL_STATIC_DRAW);
|
|
||||||
}
|
|
||||||
|
|
||||||
int idx = m_models.size();
|
|
||||||
for (Entity& ent : m_entities) {
|
|
||||||
glGenVertexArrays(1, &ent.vao);
|
|
||||||
glGenBuffers(1, &ent.vbo);
|
|
||||||
|
|
||||||
glBindVertexArray(ent.vao);
|
|
||||||
|
|
||||||
auto verts = AABBToVerts(ent.aabb, ColorForIndex(idx++));
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, ent.vbo);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(Model::Vert), verts.data(), GL_STATIC_DRAW);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glEnableVertexAttribArray(1);
|
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(Model::Vert), 0);
|
|
||||||
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Model::Vert), (void*)16);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_aabbIBO);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Light& light : m_lights) {
|
|
||||||
glGenVertexArrays(1, &light.vao);
|
|
||||||
glGenBuffers(1, &light.vbo);
|
|
||||||
|
|
||||||
glBindVertexArray(light.vao);
|
|
||||||
|
|
||||||
Model::Vert vert;
|
|
||||||
vert.pos = light.point;
|
|
||||||
vert.color = ColorForIndex(idx++);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, light.vbo);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(Model::Vert), &vert, GL_STATIC_DRAW);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glEnableVertexAttribArray(1);
|
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(Model::Vert), 0);
|
|
||||||
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Model::Vert), (void*)16);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_queryCount = m_models.size() + m_entities.size() + m_lights.size();
|
|
||||||
m_queries.reset(new GLuint[m_queryCount]);
|
|
||||||
m_queryBools.reset(new bool[m_queryCount]);
|
|
||||||
glGenQueries(GLsizei(m_queryCount), m_queries.get());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static zeus::CMatrix4f g_Proj;
|
|
||||||
|
|
||||||
static void CalculateProjMatrix() {
|
|
||||||
float znear = 0.2f;
|
|
||||||
float zfar = 1000.f;
|
|
||||||
float tfov = std::tan(zeus::degToRad(90.f * 0.5f));
|
|
||||||
float top = znear * tfov;
|
|
||||||
float bottom = -top;
|
|
||||||
float right = znear * tfov;
|
|
||||||
float left = -right;
|
|
||||||
|
|
||||||
float rml = right - left;
|
|
||||||
float rpl = right + left;
|
|
||||||
float tmb = top - bottom;
|
|
||||||
float tpb = top + bottom;
|
|
||||||
float fpn = zfar + znear;
|
|
||||||
float fmn = zfar - znear;
|
|
||||||
|
|
||||||
g_Proj = zeus::CMatrix4f(2.f * znear / rml, 0.f, rpl / rml, 0.f, 0.f, 2.f * znear / tmb, tpb / tmb, 0.f, 0.f, 0.f,
|
|
||||||
-fpn / fmn, -2.f * zfar * znear / fmn, 0.f, 0.f, -1.f, 0.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const zeus::CMatrix4f LookMATs[] = {
|
|
||||||
{// Forward
|
|
||||||
1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
|
||||||
{// Backward
|
|
||||||
-1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
|
||||||
{// Up
|
|
||||||
1.f, 0.f, 0.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
|
||||||
{// Down
|
|
||||||
1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
|
||||||
{// Left
|
|
||||||
0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
|
||||||
{// Right
|
|
||||||
0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
|
||||||
};
|
|
||||||
|
|
||||||
void VISIRenderer::RenderPVSOpaque(RGBA8* bufOut, const zeus::CVector3f& pos, bool& needTransparent) {
|
|
||||||
glViewport(0, 0, 768, 512);
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
glDepthMask(GL_TRUE);
|
|
||||||
glDepthFunc(GL_LEQUAL);
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glClearColor(0.f, 0.f, 0.f, 1.f);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
|
|
||||||
for (int j = 0; j < 6; ++j) {
|
|
||||||
GLint x = (j % 3) * 256;
|
|
||||||
GLint y = (j / 3) * 256;
|
|
||||||
glViewport(x, y, 256, 256);
|
|
||||||
|
|
||||||
zeus::CMatrix4f mv = LookMATs[j] * zeus::CTransform::Translate(-pos).toMatrix4f();
|
|
||||||
m_uniformBuffer.m_xf = g_Proj * mv;
|
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, m_uniformBufferGL);
|
|
||||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformBuffer), &m_uniformBuffer, GL_DYNAMIC_DRAW);
|
|
||||||
|
|
||||||
glUniformBlockBinding(m_program, m_uniLoc, 0);
|
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_uniformBufferGL, 0, sizeof(UniformBuffer));
|
|
||||||
|
|
||||||
zeus::CFrustum frustum;
|
|
||||||
frustum.updatePlanes(mv, g_Proj);
|
|
||||||
|
|
||||||
// Draw frontfaces
|
|
||||||
glCullFace(GL_BACK);
|
|
||||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
||||||
|
|
||||||
for (const Model& model : m_models) {
|
|
||||||
if (!frustum.aabbFrustumTest(model.aabb))
|
|
||||||
continue;
|
|
||||||
glBindVertexArray(model.vao);
|
|
||||||
for (const Model::Surface& surf : model.surfaces) {
|
|
||||||
// Non-transparents first
|
|
||||||
if (!surf.transparent)
|
|
||||||
glDrawElements(model.topology, surf.count, GL_UNSIGNED_INT,
|
|
||||||
reinterpret_cast<void*>(uintptr_t(surf.first * 4)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// m_swapFunc();
|
|
||||||
glFinish();
|
|
||||||
glReadPixels(0, 0, 768, 512, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)bufOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VISIRenderer::RenderPVSTransparent(const std::function<void(int)>& passFunc, const zeus::CVector3f& pos) {
|
|
||||||
glDepthMask(GL_FALSE);
|
|
||||||
|
|
||||||
for (int j = 0; j < 6; ++j) {
|
|
||||||
GLint x = (j % 3) * 256;
|
|
||||||
GLint y = (j / 3) * 256;
|
|
||||||
glViewport(x, y, 256, 256);
|
|
||||||
|
|
||||||
zeus::CMatrix4f mv = LookMATs[j] * zeus::CTransform::Translate(-pos).toMatrix4f();
|
|
||||||
m_uniformBuffer.m_xf = g_Proj * mv;
|
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, m_uniformBufferGL);
|
|
||||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformBuffer), &m_uniformBuffer, GL_DYNAMIC_DRAW);
|
|
||||||
|
|
||||||
glUniformBlockBinding(m_program, m_uniLoc, 0);
|
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_uniformBufferGL, 0, sizeof(UniformBuffer));
|
|
||||||
|
|
||||||
zeus::CFrustum frustum;
|
|
||||||
frustum.updatePlanes(mv, g_Proj);
|
|
||||||
|
|
||||||
memset(m_queryBools.get(), 0, m_queryCount);
|
|
||||||
|
|
||||||
int idx = 0;
|
|
||||||
for (const Model& model : m_models) {
|
|
||||||
if (!frustum.aabbFrustumTest(model.aabb)) {
|
|
||||||
++idx;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
glBindVertexArray(model.vao);
|
|
||||||
glBeginQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, m_queries[idx]);
|
|
||||||
m_queryBools[idx] = true;
|
|
||||||
for (const Model::Surface& surf : model.surfaces) {
|
|
||||||
// transparents
|
|
||||||
if (surf.transparent)
|
|
||||||
glDrawElements(model.topology, surf.count, GL_UNSIGNED_INT,
|
|
||||||
reinterpret_cast<void*>(uintptr_t(surf.first * 4)));
|
|
||||||
}
|
|
||||||
glEndQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE);
|
|
||||||
++idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < idx; ++i) {
|
|
||||||
if (m_queryBools[i]) {
|
|
||||||
GLint res;
|
|
||||||
glGetQueryObjectiv(m_queries[i], GL_QUERY_RESULT, &res);
|
|
||||||
if (res)
|
|
||||||
passFunc(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VISIRenderer::RenderPVSEntitiesAndLights(const std::function<void(int)>& passFunc,
|
|
||||||
const std::function<void(int, EPVSVisSetState)>& lightPassFunc,
|
|
||||||
const zeus::CVector3f& pos) {
|
|
||||||
glDepthMask(GL_FALSE);
|
|
||||||
|
|
||||||
for (int j = 0; j < 6; ++j) {
|
|
||||||
GLint x = (j % 3) * 256;
|
|
||||||
GLint y = (j / 3) * 256;
|
|
||||||
glViewport(x, y, 256, 256);
|
|
||||||
|
|
||||||
zeus::CMatrix4f mv = LookMATs[j] * zeus::CTransform::Translate(-pos).toMatrix4f();
|
|
||||||
m_uniformBuffer.m_xf = g_Proj * mv;
|
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, m_uniformBufferGL);
|
|
||||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformBuffer), &m_uniformBuffer, GL_DYNAMIC_DRAW);
|
|
||||||
|
|
||||||
glUniformBlockBinding(m_program, m_uniLoc, 0);
|
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_uniformBufferGL, 0, sizeof(UniformBuffer));
|
|
||||||
|
|
||||||
zeus::CFrustum frustum;
|
|
||||||
frustum.updatePlanes(mv, g_Proj);
|
|
||||||
|
|
||||||
memset(m_queryBools.get(), 0, m_queryCount);
|
|
||||||
|
|
||||||
int idx = m_models.size();
|
|
||||||
for (const Entity& ent : m_entities) {
|
|
||||||
if (!frustum.aabbFrustumTest(ent.aabb)) {
|
|
||||||
++idx;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
glBindVertexArray(ent.vao);
|
|
||||||
m_queryBools[idx] = true;
|
|
||||||
glBeginQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, m_queries[idx]);
|
|
||||||
glDrawElements(GL_TRIANGLE_STRIP, 20, GL_UNSIGNED_INT, 0);
|
|
||||||
glEndQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE);
|
|
||||||
++idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const Light& light : m_lights) {
|
|
||||||
if (!frustum.pointFrustumTest(light.point)) {
|
|
||||||
++idx;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
glBindVertexArray(light.vao);
|
|
||||||
m_queryBools[idx] = true;
|
|
||||||
glBeginQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, m_queries[idx]);
|
|
||||||
glDrawArrays(GL_POINTS, 0, 1);
|
|
||||||
glEndQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE);
|
|
||||||
++idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
idx = m_models.size();
|
|
||||||
for (const Entity& ent : m_entities) {
|
|
||||||
(void)ent;
|
|
||||||
if (m_queryBools[idx]) {
|
|
||||||
GLint res;
|
|
||||||
glGetQueryObjectiv(m_queries[idx], GL_QUERY_RESULT, &res);
|
|
||||||
if (res)
|
|
||||||
passFunc(idx);
|
|
||||||
}
|
|
||||||
++idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lightIdx = 0;
|
|
||||||
for (const Light& light : m_lights) {
|
|
||||||
if (m_queryBools[idx]) {
|
|
||||||
GLint res;
|
|
||||||
glGetQueryObjectiv(m_queries[idx], GL_QUERY_RESULT, &res);
|
|
||||||
EPVSVisSetState state =
|
|
||||||
m_totalAABB.pointInside(light.point) ? EPVSVisSetState::EndOfTree : EPVSVisSetState::OutOfBounds;
|
|
||||||
if (res && state == EPVSVisSetState::EndOfTree)
|
|
||||||
state = EPVSVisSetState::NodeFound;
|
|
||||||
lightPassFunc(lightIdx, state);
|
|
||||||
}
|
|
||||||
++lightIdx;
|
|
||||||
++idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VISIRenderer::Run(FPercent updatePercent) {
|
void VISIRenderer::Run(FPercent updatePercent) {
|
||||||
m_updatePercent = updatePercent;
|
m_updatePercent = updatePercent;
|
||||||
CalculateProjMatrix();
|
|
||||||
|
|
||||||
if (glewInit() != GLEW_OK) {
|
|
||||||
Log.report(logvisor::Error, FMT_STRING("unable to init glew"));
|
|
||||||
m_return = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GLEW_ARB_occlusion_query2) {
|
|
||||||
Log.report(logvisor::Error, FMT_STRING("GL_ARB_occlusion_query2 extension not present"));
|
|
||||||
m_return = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SetupShaders()) {
|
if (!SetupShaders()) {
|
||||||
m_return = 1;
|
m_return = 1;
|
||||||
|
@ -456,7 +194,7 @@ void VISIRenderer::Run(FPercent updatePercent) {
|
||||||
zeus::CColor color = ColorForIndex(i);
|
zeus::CColor color = ColorForIndex(i);
|
||||||
Model& model = m_models[i];
|
Model& model = m_models[i];
|
||||||
uint32_t topology = r.readUint32Big();
|
uint32_t topology = r.readUint32Big();
|
||||||
model.topology = topology ? GL_TRIANGLE_STRIP : GL_TRIANGLES;
|
model.topology = static_cast<hecl::HMDLTopology>(topology);
|
||||||
|
|
||||||
uint32_t vertCount = r.readUint32Big();
|
uint32_t vertCount = r.readUint32Big();
|
||||||
model.verts.reserve(vertCount);
|
model.verts.reserve(vertCount);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "boo/graphicsdev/glew.h"
|
|
||||||
#include "hecl/SystemChar.hpp"
|
#include "hecl/SystemChar.hpp"
|
||||||
|
#include "hecl/HMDLMeta.hpp"
|
||||||
#include "zeus/CColor.hpp"
|
#include "zeus/CColor.hpp"
|
||||||
#include "zeus/CMatrix4f.hpp"
|
#include "zeus/CMatrix4f.hpp"
|
||||||
#include "zeus/CAABox.hpp"
|
#include "zeus/CAABox.hpp"
|
||||||
|
@ -13,18 +13,9 @@ enum class EPVSVisSetState { EndOfTree, NodeFound, OutOfBounds };
|
||||||
class VISIRenderer {
|
class VISIRenderer {
|
||||||
friend struct VISIBuilder;
|
friend struct VISIBuilder;
|
||||||
|
|
||||||
int m_argc;
|
public:
|
||||||
const hecl::SystemChar** m_argv;
|
|
||||||
int m_return = 0;
|
|
||||||
|
|
||||||
zeus::CAABox m_totalAABB;
|
|
||||||
|
|
||||||
struct UniformBuffer {
|
|
||||||
zeus::CMatrix4f m_xf;
|
|
||||||
} m_uniformBuffer;
|
|
||||||
|
|
||||||
struct Model {
|
struct Model {
|
||||||
GLenum topology;
|
hecl::HMDLTopology topology;
|
||||||
zeus::CAABox aabb;
|
zeus::CAABox aabb;
|
||||||
|
|
||||||
struct Vert {
|
struct Vert {
|
||||||
|
@ -34,7 +25,6 @@ class VISIRenderer {
|
||||||
std::vector<Vert> verts;
|
std::vector<Vert> verts;
|
||||||
|
|
||||||
std::vector<uint32_t> idxs;
|
std::vector<uint32_t> idxs;
|
||||||
GLuint vbo, ibo, vao;
|
|
||||||
|
|
||||||
struct Surface {
|
struct Surface {
|
||||||
uint32_t first;
|
uint32_t first;
|
||||||
|
@ -47,32 +37,29 @@ class VISIRenderer {
|
||||||
struct Entity {
|
struct Entity {
|
||||||
uint32_t entityId;
|
uint32_t entityId;
|
||||||
zeus::CAABox aabb;
|
zeus::CAABox aabb;
|
||||||
GLuint vbo, vao;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Light {
|
struct Light {
|
||||||
zeus::CVector3f point;
|
zeus::CVector3f point;
|
||||||
GLuint vbo, vao;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GLuint m_vtxShader, m_fragShader, m_program, m_uniLoc;
|
protected:
|
||||||
GLuint m_uniformBufferGL;
|
int m_argc;
|
||||||
GLuint m_aabbIBO;
|
const hecl::SystemChar** m_argv;
|
||||||
bool SetupShaders();
|
int m_return = 0;
|
||||||
|
|
||||||
|
zeus::CAABox m_totalAABB;
|
||||||
|
|
||||||
|
virtual bool SetupShaders() = 0;
|
||||||
|
|
||||||
std::vector<Model> m_models;
|
std::vector<Model> m_models;
|
||||||
std::vector<Entity> m_entities;
|
std::vector<Entity> m_entities;
|
||||||
std::vector<Light> m_lights;
|
std::vector<Light> m_lights;
|
||||||
bool SetupVertexBuffersAndFormats();
|
virtual bool SetupVertexBuffersAndFormats() = 0;
|
||||||
|
virtual void SetupRenderPass(const zeus::CVector3f& pos) = 0;
|
||||||
size_t m_queryCount;
|
|
||||||
std::unique_ptr<GLuint[]> m_queries;
|
|
||||||
std::unique_ptr<bool[]> m_queryBools;
|
|
||||||
|
|
||||||
FPercent m_updatePercent;
|
FPercent m_updatePercent;
|
||||||
|
|
||||||
static std::vector<Model::Vert> AABBToVerts(const zeus::CAABox& aabb, const zeus::CColor& color);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool m_terminate = false;
|
bool m_terminate = false;
|
||||||
struct RGBA8 {
|
struct RGBA8 {
|
||||||
|
@ -85,10 +72,13 @@ public:
|
||||||
VISIRenderer(int argc, const hecl::SystemChar** argv) : m_argc(argc), m_argv(argv) {}
|
VISIRenderer(int argc, const hecl::SystemChar** argv) : m_argc(argc), m_argv(argv) {}
|
||||||
void Run(FPercent updatePercent);
|
void Run(FPercent updatePercent);
|
||||||
void Terminate();
|
void Terminate();
|
||||||
void RenderPVSOpaque(RGBA8* bufOut, const zeus::CVector3f& pos, bool& needTransparent);
|
virtual void RenderPVSOpaque(RGBA8* bufOut, bool& needTransparent) = 0;
|
||||||
void RenderPVSTransparent(const std::function<void(int)>& passFunc, const zeus::CVector3f& pos);
|
virtual void RenderPVSTransparent(const std::function<void(int)>& passFunc) = 0;
|
||||||
void RenderPVSEntitiesAndLights(const std::function<void(int)>& passFunc,
|
virtual void RenderPVSEntitiesAndLights(const std::function<void(int)>& passFunc,
|
||||||
const std::function<void(int, EPVSVisSetState)>& lightPassFunc,
|
const std::function<void(int, EPVSVisSetState)>& lightPassFunc) = 0;
|
||||||
const zeus::CVector3f& pos);
|
|
||||||
int ReturnVal() const { return m_return; }
|
int ReturnVal() const { return m_return; }
|
||||||
|
|
||||||
|
static std::vector<Model::Vert> AABBToVerts(const zeus::CAABox& aabb, const zeus::CColor& color);
|
||||||
|
static zeus::CColor ColorForIndex(uint32_t i);
|
||||||
|
static void* makePNGBuffer(unsigned char* rgba, int width, int height, size_t* outsize);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "VISIRenderer.hpp"
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
#import <MetalKit/MetalKit.h>
|
||||||
|
|
||||||
|
@interface MetalRenderer : NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
class VISIRendererMetal : public VISIRenderer {
|
||||||
|
MetalRenderer* view;
|
||||||
|
|
||||||
|
bool SetupShaders() override;
|
||||||
|
bool SetupVertexBuffersAndFormats() override;
|
||||||
|
void SetupRenderPass(const zeus::CVector3f& pos) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
VISIRendererMetal(int argc, const hecl::SystemChar** argv) : VISIRenderer(argc, argv) {
|
||||||
|
view = [[MetalRenderer alloc] init];
|
||||||
|
}
|
||||||
|
void RenderPVSOpaque(RGBA8* out, bool& needTransparent) override;
|
||||||
|
void RenderPVSTransparent(const std::function<void(int)>& passFunc) override;
|
||||||
|
void RenderPVSEntitiesAndLights(const std::function<void(int)>& passFunc,
|
||||||
|
const std::function<void(int, EPVSVisSetState)>& lightPassFunc) override;
|
||||||
|
};
|
|
@ -0,0 +1,480 @@
|
||||||
|
#include "VISIRendererMetal.hh"
|
||||||
|
#include "ShaderTypes.h"
|
||||||
|
|
||||||
|
#include <zeus/CFrustum.hpp>
|
||||||
|
|
||||||
|
static zeus::CMatrix4f g_Proj;
|
||||||
|
|
||||||
|
constexpr zeus::CMatrix4f VulkanCorrect(1.f, 0.f, 0.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.5f, 0.5f + FLT_EPSILON,
|
||||||
|
0.f, 0.f, 0.f, 1.f);
|
||||||
|
|
||||||
|
static void CalculateProjMatrix() {
|
||||||
|
float znear = 0.2f;
|
||||||
|
float zfar = 1000.f;
|
||||||
|
float tfov = std::tan(zeus::degToRad(90.f * 0.5f));
|
||||||
|
float top = znear * tfov;
|
||||||
|
float bottom = -top;
|
||||||
|
float right = znear * tfov;
|
||||||
|
float left = -right;
|
||||||
|
|
||||||
|
float rml = right - left;
|
||||||
|
float rpl = right + left;
|
||||||
|
float tmb = top - bottom;
|
||||||
|
float tpb = top + bottom;
|
||||||
|
float fpn = zfar + znear;
|
||||||
|
float fmn = zfar - znear;
|
||||||
|
|
||||||
|
zeus::CMatrix4f mat2{
|
||||||
|
2.f * znear / rml, 0.f, rpl / rml, 0.f, 0.f, 2.f * znear / tmb, tpb / tmb, 0.f, 0.f, 0.f, -fpn / fmn,
|
||||||
|
-2.f * zfar * znear / fmn, 0.f, 0.f, -1.f, 0.f};
|
||||||
|
g_Proj = VulkanCorrect * mat2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr std::array<uint16_t, 20> AABBIdxs{0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 1, 7, 3, 5, 5, 0, 0, 2, 6, 4};
|
||||||
|
|
||||||
|
static const zeus::CMatrix4f LookMATs[] = {
|
||||||
|
{// Forward
|
||||||
|
1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
||||||
|
{// Backward
|
||||||
|
-1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
||||||
|
{// Up
|
||||||
|
1.f, 0.f, 0.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
||||||
|
{// Down
|
||||||
|
1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
||||||
|
{// Left
|
||||||
|
0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
||||||
|
{// Right
|
||||||
|
0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
||||||
|
};
|
||||||
|
|
||||||
|
using Vertex = VISIRenderer::Model::Vert;
|
||||||
|
|
||||||
|
@implementation MetalRenderer {
|
||||||
|
MTLPixelFormat _pixelFormat;
|
||||||
|
MTLPixelFormat _depthPixelFormat;
|
||||||
|
|
||||||
|
id<MTLDevice> _device;
|
||||||
|
id<MTLLibrary> _library;
|
||||||
|
id<MTLCommandQueue> _commandQueue;
|
||||||
|
id<MTLRenderPipelineState> _pipelineState;
|
||||||
|
id<MTLDepthStencilState> _depthState;
|
||||||
|
id<MTLDepthStencilState> _depthStateNoWrite;
|
||||||
|
dispatch_semaphore_t _semaphore;
|
||||||
|
id<MTLBuffer> _uniformBuffer;
|
||||||
|
id<MTLBuffer> _vertexBuffer;
|
||||||
|
id<MTLBuffer> _indexBuffer;
|
||||||
|
id<MTLBuffer> _modelQueryBuffer;
|
||||||
|
id<MTLBuffer> _entityLightQueryBuffer;
|
||||||
|
id<MTLBuffer> _aabbIndexBuffer;
|
||||||
|
id<MTLTexture> _renderTexture;
|
||||||
|
id<MTLTexture> _depthTexture;
|
||||||
|
|
||||||
|
std::array<zeus::CFrustum, 6> _frustums;
|
||||||
|
NSUInteger _entityVertStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (bool)setup {
|
||||||
|
CalculateProjMatrix();
|
||||||
|
|
||||||
|
// Create device.
|
||||||
|
_device = MTLCreateSystemDefaultDevice();
|
||||||
|
|
||||||
|
// Set view settings.
|
||||||
|
_pixelFormat = MTLPixelFormatRGBA8Unorm;
|
||||||
|
_depthPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
|
||||||
|
|
||||||
|
// Load shaders.
|
||||||
|
NSError *error = nil;
|
||||||
|
_library = [_device newLibraryWithFile:@"Shader.metallib" error:&error];
|
||||||
|
if (_library == nullptr) {
|
||||||
|
NSLog(@"Failed to load library. error %@", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
id<MTLFunction> vertFunc = [_library newFunctionWithName:@"vertexShader"];
|
||||||
|
id<MTLFunction> fragFunc = [_library newFunctionWithName:@"fragmentShader"];
|
||||||
|
|
||||||
|
// Create render texture.
|
||||||
|
MTLTextureDescriptor *renderTexDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:_pixelFormat
|
||||||
|
width:768
|
||||||
|
height:512
|
||||||
|
mipmapped:NO];
|
||||||
|
renderTexDesc.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||||
|
_renderTexture = [_device newTextureWithDescriptor:renderTexDesc];
|
||||||
|
|
||||||
|
// Create depth texture.
|
||||||
|
MTLTextureDescriptor *depthTexDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:_depthPixelFormat
|
||||||
|
width:768
|
||||||
|
height:512
|
||||||
|
mipmapped:NO];
|
||||||
|
depthTexDesc.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||||
|
_depthTexture = [_device newTextureWithDescriptor:depthTexDesc];
|
||||||
|
|
||||||
|
// Create depth state.
|
||||||
|
MTLDepthStencilDescriptor *depthDesc = [[MTLDepthStencilDescriptor alloc] init];
|
||||||
|
depthDesc.depthCompareFunction = MTLCompareFunctionLessEqual;
|
||||||
|
depthDesc.depthWriteEnabled = YES;
|
||||||
|
_depthState = [_device newDepthStencilStateWithDescriptor:depthDesc];
|
||||||
|
|
||||||
|
// Create depth state (no write).
|
||||||
|
MTLDepthStencilDescriptor *depthDescNoWrite = [[MTLDepthStencilDescriptor alloc] init];
|
||||||
|
depthDescNoWrite.depthCompareFunction = MTLCompareFunctionLessEqual;
|
||||||
|
depthDescNoWrite.depthWriteEnabled = NO;
|
||||||
|
_depthStateNoWrite = [_device newDepthStencilStateWithDescriptor:depthDescNoWrite];
|
||||||
|
|
||||||
|
// Create vertex descriptor.
|
||||||
|
MTLVertexDescriptor *vertDesc = [[MTLVertexDescriptor alloc] init];
|
||||||
|
vertDesc.attributes[VertexAttributePosition].format = MTLVertexFormatFloat3;
|
||||||
|
vertDesc.attributes[VertexAttributePosition].offset = offsetof(Vertex, pos);
|
||||||
|
vertDesc.attributes[VertexAttributePosition].bufferIndex = BufferIndexVertex;
|
||||||
|
vertDesc.attributes[VertexAttributeColor].format = MTLVertexFormatFloat4;
|
||||||
|
vertDesc.attributes[VertexAttributeColor].offset = offsetof(Vertex, color);
|
||||||
|
vertDesc.attributes[VertexAttributeColor].bufferIndex = BufferIndexVertex;
|
||||||
|
vertDesc.layouts[BufferIndexVertex].stride = sizeof(Vertex);
|
||||||
|
vertDesc.layouts[BufferIndexVertex].stepRate = 1;
|
||||||
|
vertDesc.layouts[BufferIndexVertex].stepFunction = MTLVertexStepFunctionPerVertex;
|
||||||
|
|
||||||
|
// Create pipeline state.
|
||||||
|
MTLRenderPipelineDescriptor *pipelineDesc = [[MTLRenderPipelineDescriptor alloc] init];
|
||||||
|
pipelineDesc.rasterSampleCount = 1;
|
||||||
|
pipelineDesc.vertexFunction = vertFunc;
|
||||||
|
pipelineDesc.fragmentFunction = fragFunc;
|
||||||
|
pipelineDesc.vertexDescriptor = vertDesc;
|
||||||
|
pipelineDesc.colorAttachments[0].pixelFormat = _pixelFormat;
|
||||||
|
pipelineDesc.depthAttachmentPixelFormat = _depthPixelFormat;
|
||||||
|
_pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
|
||||||
|
if (_pipelineState == nullptr) {
|
||||||
|
NSLog(@"Failed to create pipeline state, error %@", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (bool)setupModels:(std::vector<VISIRenderer::Model> &)models
|
||||||
|
entities:(std::vector<VISIRenderer::Entity> &)entities
|
||||||
|
lights:(std::vector<VISIRenderer::Light> &)lights {
|
||||||
|
NSUInteger vertCount = 0;
|
||||||
|
NSUInteger indexCount = 0;
|
||||||
|
for (const auto &model : models) {
|
||||||
|
vertCount += model.verts.size();
|
||||||
|
indexCount += model.idxs.size();
|
||||||
|
}
|
||||||
|
_entityVertStart = vertCount;
|
||||||
|
vertCount += 8 * entities.size();
|
||||||
|
vertCount += lights.size();
|
||||||
|
_vertexBuffer = [_device newBufferWithLength:vertCount * sizeof(Vertex) options:MTLResourceStorageModeManaged];
|
||||||
|
_indexBuffer = [_device newBufferWithLength:indexCount * sizeof(uint32_t) options:MTLResourceStorageModeManaged];
|
||||||
|
_modelQueryBuffer = [_device newBufferWithLength:models.size() * 6 * sizeof(uint64_t)
|
||||||
|
options:MTLResourceStorageModeManaged];
|
||||||
|
_entityLightQueryBuffer = [_device newBufferWithLength:(entities.size() + lights.size()) * 6 * sizeof(uint64_t)
|
||||||
|
options:MTLResourceStorageModeManaged];
|
||||||
|
|
||||||
|
auto *buffer = static_cast<Vertex *>([_vertexBuffer contents]);
|
||||||
|
auto *indexBuffer = static_cast<uint32_t *>([_indexBuffer contents]);
|
||||||
|
for (const auto &model : models) {
|
||||||
|
memcpy(buffer, model.verts.data(), model.verts.size() * sizeof(Vertex));
|
||||||
|
memcpy(indexBuffer, model.idxs.data(), model.idxs.size() * sizeof(uint32_t));
|
||||||
|
buffer += model.verts.size();
|
||||||
|
indexBuffer += model.idxs.size();
|
||||||
|
}
|
||||||
|
auto idx = static_cast<uint32_t>(models.size());
|
||||||
|
for (const auto &ent : entities) {
|
||||||
|
auto verts = VISIRenderer::AABBToVerts(ent.aabb, VISIRenderer::ColorForIndex(idx++));
|
||||||
|
memcpy(buffer, verts.data(), verts.size() * sizeof(Vertex));
|
||||||
|
buffer += verts.size();
|
||||||
|
}
|
||||||
|
for (const auto &light : lights) {
|
||||||
|
auto *vert = buffer++;
|
||||||
|
vert->pos = light.point;
|
||||||
|
vert->color = VISIRenderer::ColorForIndex(idx++);
|
||||||
|
}
|
||||||
|
[_vertexBuffer didModifyRange:NSMakeRange(0, [_vertexBuffer length])];
|
||||||
|
[_indexBuffer didModifyRange:NSMakeRange(0, [_indexBuffer length])];
|
||||||
|
|
||||||
|
_uniformBuffer = [_device newBufferWithLength:sizeof(Uniforms) * 6 options:MTLResourceStorageModeManaged];
|
||||||
|
_aabbIndexBuffer = [_device newBufferWithBytes:AABBIdxs.data()
|
||||||
|
length:AABBIdxs.size() * sizeof(uint16_t)
|
||||||
|
options:MTLResourceStorageModeManaged];
|
||||||
|
|
||||||
|
_semaphore = dispatch_semaphore_create(0);
|
||||||
|
_commandQueue = [_device newCommandQueue];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setupRenderPass:(const zeus::CVector3f &)pos {
|
||||||
|
auto posMat = zeus::CTransform::Translate(-pos).toMatrix4f();
|
||||||
|
auto *buffer = static_cast<Uniforms *>([_uniformBuffer contents]);
|
||||||
|
for (uint16_t j = 0; j < 6; ++j) {
|
||||||
|
static_assert(sizeof(zeus::CMatrix4f) == sizeof(matrix_float4x4));
|
||||||
|
zeus::CMatrix4f modelView = LookMATs[j] * posMat;
|
||||||
|
_frustums[j].updatePlanes(modelView, g_Proj);
|
||||||
|
memcpy(&buffer->projectionMatrix, &g_Proj, sizeof(matrix_float4x4));
|
||||||
|
memcpy(&buffer->modelViewMatrix, &modelView, sizeof(matrix_float4x4));
|
||||||
|
buffer++;
|
||||||
|
}
|
||||||
|
[_uniformBuffer didModifyRange:NSMakeRange(0, [_uniformBuffer length])];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)renderPVSOpaque:(std::vector<VISIRenderer::Model> &)models
|
||||||
|
out:(VISIRenderer::RGBA8 *)out
|
||||||
|
needTransparent:(bool &)needTransparent {
|
||||||
|
id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
|
||||||
|
|
||||||
|
__block dispatch_semaphore_t semaphore = _semaphore;
|
||||||
|
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
|
||||||
|
dispatch_semaphore_signal(semaphore);
|
||||||
|
}];
|
||||||
|
|
||||||
|
MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||||
|
passDescriptor.colorAttachments[0].texture = _renderTexture;
|
||||||
|
passDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||||
|
passDescriptor.depthAttachment.texture = _depthTexture;
|
||||||
|
passDescriptor.depthAttachment.storeAction = MTLStoreActionStore; // stored for following render passes
|
||||||
|
id<MTLRenderCommandEncoder> encoder = [commandBuffer renderCommandEncoderWithDescriptor:passDescriptor];
|
||||||
|
|
||||||
|
[encoder setDepthStencilState:_depthState];
|
||||||
|
[encoder setRenderPipelineState:_pipelineState];
|
||||||
|
[encoder setCullMode:MTLCullModeBack];
|
||||||
|
[encoder setVertexBuffer:_vertexBuffer offset:0 atIndex:BufferIndexVertex];
|
||||||
|
[encoder setVertexBuffer:_uniformBuffer offset:0 atIndex:BufferIndexUniforms];
|
||||||
|
|
||||||
|
for (int j = 0; j < 6; ++j) {
|
||||||
|
GLint x = (j % 3) * 256;
|
||||||
|
GLint y = (j / 3) * 256;
|
||||||
|
[encoder setViewport:{x, y, 256, 256, 0, 1}];
|
||||||
|
if (j > 0) {
|
||||||
|
[encoder setVertexBufferOffset:j * sizeof(Uniforms) atIndex:BufferIndexUniforms];
|
||||||
|
}
|
||||||
|
NSUInteger vertexBufferOffset = 0;
|
||||||
|
NSUInteger indexBufferOffset = 0;
|
||||||
|
for (const auto &model : models) {
|
||||||
|
if (_frustums[j].aabbFrustumTest(model.aabb)) {
|
||||||
|
[encoder setVertexBufferOffset:vertexBufferOffset atIndex:BufferIndexVertex];
|
||||||
|
for (const auto &surf : model.surfaces) {
|
||||||
|
// Non-transparents first
|
||||||
|
if (surf.transparent) {
|
||||||
|
needTransparent = true;
|
||||||
|
} else {
|
||||||
|
MTLPrimitiveType type = model.topology == hecl::HMDLTopology::TriStrips ? MTLPrimitiveTypeTriangleStrip
|
||||||
|
: MTLPrimitiveTypeTriangle;
|
||||||
|
[encoder drawIndexedPrimitives:type
|
||||||
|
indexCount:surf.count
|
||||||
|
indexType:MTLIndexTypeUInt32
|
||||||
|
indexBuffer:_indexBuffer
|
||||||
|
indexBufferOffset:indexBufferOffset + surf.first * sizeof(uint32_t)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vertexBufferOffset += model.verts.size() * sizeof(Vertex);
|
||||||
|
indexBufferOffset += model.idxs.size() * sizeof(uint32_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[encoder endEncoding];
|
||||||
|
[commandBuffer commit];
|
||||||
|
|
||||||
|
dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
|
||||||
|
|
||||||
|
[_renderTexture getBytes:out
|
||||||
|
bytesPerRow:sizeof(VISIRenderer::RGBA8) * _renderTexture.width
|
||||||
|
fromRegion:MTLRegionMake2D(0, 0, _renderTexture.width, _renderTexture.height)
|
||||||
|
mipmapLevel:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)renderPVSTransparent:(std::vector<VISIRenderer::Model> &)models
|
||||||
|
passFunc:(const std::function<void(int)> &)passFunc {
|
||||||
|
// Zero out query buffer
|
||||||
|
memset([_modelQueryBuffer contents], 0, [_modelQueryBuffer length]);
|
||||||
|
[_modelQueryBuffer didModifyRange:NSMakeRange(0, [_modelQueryBuffer length])];
|
||||||
|
|
||||||
|
id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
|
||||||
|
|
||||||
|
__block dispatch_semaphore_t semaphore = _semaphore;
|
||||||
|
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
|
||||||
|
dispatch_semaphore_signal(semaphore);
|
||||||
|
}];
|
||||||
|
|
||||||
|
MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||||
|
passDescriptor.colorAttachments[0].texture = _renderTexture;
|
||||||
|
passDescriptor.colorAttachments[0].storeAction = MTLStoreActionDontCare; // no longer care about the render texture
|
||||||
|
passDescriptor.depthAttachment.texture = _depthTexture;
|
||||||
|
passDescriptor.depthAttachment.loadAction = MTLLoadActionLoad;
|
||||||
|
passDescriptor.depthAttachment.storeAction = MTLStoreActionStore; // still stored for following render passes
|
||||||
|
passDescriptor.visibilityResultBuffer = _modelQueryBuffer;
|
||||||
|
id<MTLRenderCommandEncoder> encoder = [commandBuffer renderCommandEncoderWithDescriptor:passDescriptor];
|
||||||
|
|
||||||
|
[encoder setDepthStencilState:_depthStateNoWrite];
|
||||||
|
[encoder setRenderPipelineState:_pipelineState];
|
||||||
|
[encoder setCullMode:MTLCullModeBack];
|
||||||
|
[encoder setVertexBuffer:_vertexBuffer offset:0 atIndex:BufferIndexVertex];
|
||||||
|
[encoder setVertexBuffer:_uniformBuffer offset:0 atIndex:BufferIndexUniforms];
|
||||||
|
|
||||||
|
NSUInteger queryCount = 0;
|
||||||
|
for (int j = 0; j < 6; ++j) {
|
||||||
|
GLint x = (j % 3) * 256;
|
||||||
|
GLint y = (j / 3) * 256;
|
||||||
|
[encoder setViewport:{x, y, 256, 256, 0, 1}];
|
||||||
|
if (j > 0) {
|
||||||
|
[encoder setVertexBufferOffset:j * sizeof(Uniforms) atIndex:BufferIndexUniforms];
|
||||||
|
}
|
||||||
|
NSUInteger vertexBufferOffset = 0;
|
||||||
|
NSUInteger indexBufferOffset = 0;
|
||||||
|
for (const auto &model : models) {
|
||||||
|
if (_frustums[j].aabbFrustumTest(model.aabb)) {
|
||||||
|
[encoder setVertexBufferOffset:vertexBufferOffset atIndex:BufferIndexVertex];
|
||||||
|
[encoder setVisibilityResultMode:MTLVisibilityResultModeBoolean offset:queryCount * sizeof(uint64_t)];
|
||||||
|
for (const auto &surf : model.surfaces) {
|
||||||
|
// Only transparent surfaces
|
||||||
|
if (surf.transparent) {
|
||||||
|
MTLPrimitiveType type = model.topology == hecl::HMDLTopology::TriStrips ? MTLPrimitiveTypeTriangleStrip
|
||||||
|
: MTLPrimitiveTypeTriangle;
|
||||||
|
[encoder drawIndexedPrimitives:type
|
||||||
|
indexCount:surf.count
|
||||||
|
indexType:MTLIndexTypeUInt32
|
||||||
|
indexBuffer:_indexBuffer
|
||||||
|
indexBufferOffset:indexBufferOffset + surf.first * sizeof(uint32_t)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vertexBufferOffset += model.verts.size() * sizeof(Vertex);
|
||||||
|
indexBufferOffset += model.idxs.size() * sizeof(uint32_t);
|
||||||
|
++queryCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[encoder endEncoding];
|
||||||
|
[commandBuffer commit];
|
||||||
|
|
||||||
|
dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
|
||||||
|
|
||||||
|
auto *queries = static_cast<uint64_t *>([_modelQueryBuffer contents]);
|
||||||
|
for (int i = 0; i < models.size(); ++i) {
|
||||||
|
for (int j = 0; j < 6; ++j) {
|
||||||
|
if (queries[i + j * models.size()] != 0u) {
|
||||||
|
passFunc(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)renderPVSEntities:(std::vector<VISIRenderer::Entity> &)entities
|
||||||
|
entityPassFunc:(const std::function<void(int)> &)entityPassFunc
|
||||||
|
lights:(std::vector<VISIRenderer::Light> &)lights
|
||||||
|
lightPassFunc:(const std::function<void(int, EPVSVisSetState)> &)lightPassFunc
|
||||||
|
totalAABB:(const zeus::CAABox &)totalAABB {
|
||||||
|
// Zero out query buffer
|
||||||
|
memset([_entityLightQueryBuffer contents], 0, [_entityLightQueryBuffer length]);
|
||||||
|
[_entityLightQueryBuffer didModifyRange:NSMakeRange(0, [_entityLightQueryBuffer length])];
|
||||||
|
|
||||||
|
id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
|
||||||
|
|
||||||
|
__block dispatch_semaphore_t semaphore = _semaphore;
|
||||||
|
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
|
||||||
|
dispatch_semaphore_signal(semaphore);
|
||||||
|
}];
|
||||||
|
|
||||||
|
MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||||
|
passDescriptor.colorAttachments[0].texture = _renderTexture;
|
||||||
|
passDescriptor.colorAttachments[0].storeAction = MTLStoreActionDontCare; // no longer care about the render texture
|
||||||
|
passDescriptor.depthAttachment.texture = _depthTexture;
|
||||||
|
passDescriptor.depthAttachment.loadAction = MTLLoadActionLoad;
|
||||||
|
passDescriptor.visibilityResultBuffer = _entityLightQueryBuffer;
|
||||||
|
id<MTLRenderCommandEncoder> encoder = [commandBuffer renderCommandEncoderWithDescriptor:passDescriptor];
|
||||||
|
|
||||||
|
[encoder setDepthStencilState:_depthStateNoWrite];
|
||||||
|
[encoder setRenderPipelineState:_pipelineState];
|
||||||
|
[encoder setCullMode:MTLCullModeBack];
|
||||||
|
[encoder setVertexBuffer:_vertexBuffer offset:0 atIndex:BufferIndexVertex];
|
||||||
|
[encoder setVertexBuffer:_uniformBuffer offset:0 atIndex:BufferIndexUniforms];
|
||||||
|
|
||||||
|
NSUInteger queryCount = 0;
|
||||||
|
for (int j = 0; j < 6; ++j) {
|
||||||
|
GLint x = (j % 3) * 256;
|
||||||
|
GLint y = (j / 3) * 256;
|
||||||
|
[encoder setViewport:{x, y, 256, 256, 0, 1}];
|
||||||
|
if (j > 0) {
|
||||||
|
[encoder setVertexBufferOffset:j * sizeof(Uniforms) atIndex:BufferIndexUniforms];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSUInteger vertexBufferOffset = _entityVertStart * sizeof(Vertex);
|
||||||
|
|
||||||
|
for (const auto &ent : entities) {
|
||||||
|
if (_frustums[j].aabbFrustumTest(ent.aabb)) {
|
||||||
|
[encoder setVertexBufferOffset:vertexBufferOffset atIndex:BufferIndexVertex];
|
||||||
|
[encoder setVisibilityResultMode:MTLVisibilityResultModeBoolean offset:queryCount * sizeof(uint64_t)];
|
||||||
|
[encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangleStrip
|
||||||
|
indexCount:20
|
||||||
|
indexType:MTLIndexTypeUInt32
|
||||||
|
indexBuffer:_aabbIndexBuffer
|
||||||
|
indexBufferOffset:0];
|
||||||
|
}
|
||||||
|
vertexBufferOffset += 20 * sizeof(Vertex);
|
||||||
|
++queryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &light : lights) {
|
||||||
|
if (_frustums[j].pointFrustumTest(light.point)) {
|
||||||
|
[encoder setVertexBufferOffset:vertexBufferOffset atIndex:BufferIndexVertex];
|
||||||
|
[encoder setVisibilityResultMode:MTLVisibilityResultModeBoolean offset:queryCount * sizeof(uint64_t)];
|
||||||
|
[encoder drawPrimitives:MTLPrimitiveTypePoint vertexStart:0 vertexCount:1];
|
||||||
|
}
|
||||||
|
vertexBufferOffset += sizeof(Vertex);
|
||||||
|
++queryCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[encoder endEncoding];
|
||||||
|
[commandBuffer commit];
|
||||||
|
|
||||||
|
dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
|
||||||
|
|
||||||
|
NSUInteger total = entities.size() + lights.size();
|
||||||
|
auto *queries = static_cast<uint64_t *>([_entityLightQueryBuffer contents]);
|
||||||
|
for (int i = 0; i < entities.size(); ++i) {
|
||||||
|
for (int j = 0; j < 6; ++j) {
|
||||||
|
if (queries[i + j * total] != 0u) {
|
||||||
|
entityPassFunc(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < lights.size(); ++i) {
|
||||||
|
bool pointInside = totalAABB.pointInside(lights[i].point);
|
||||||
|
EPVSVisSetState state = pointInside ? EPVSVisSetState::EndOfTree : EPVSVisSetState::OutOfBounds;
|
||||||
|
if (pointInside) {
|
||||||
|
for (int j = 0; j < 6; ++j) {
|
||||||
|
if (queries[entities.size() + i + j * total] != 0u) {
|
||||||
|
state = EPVSVisSetState::NodeFound;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lightPassFunc(i, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
bool VISIRendererMetal::SetupShaders() { return [view setup]; }
|
||||||
|
|
||||||
|
bool VISIRendererMetal::SetupVertexBuffersAndFormats() {
|
||||||
|
return [view setupModels:m_models entities:m_entities lights:m_lights];
|
||||||
|
}
|
||||||
|
|
||||||
|
void VISIRendererMetal::SetupRenderPass(const zeus::CVector3f &pos) { [view setupRenderPass:pos]; }
|
||||||
|
|
||||||
|
void VISIRendererMetal::RenderPVSOpaque(RGBA8 *bufOut, bool &needTransparent) {
|
||||||
|
[view renderPVSOpaque:m_models out:bufOut needTransparent:needTransparent];
|
||||||
|
}
|
||||||
|
|
||||||
|
void VISIRendererMetal::RenderPVSTransparent(const std::function<void(int)> &passFunc) {
|
||||||
|
[view renderPVSTransparent:m_models passFunc:passFunc];
|
||||||
|
}
|
||||||
|
|
||||||
|
void VISIRendererMetal::RenderPVSEntitiesAndLights(const std::function<void(int)> &passFunc,
|
||||||
|
const std::function<void(int, EPVSVisSetState)> &lightPassFunc) {
|
||||||
|
[view renderPVSEntities:m_entities
|
||||||
|
entityPassFunc:passFunc
|
||||||
|
lights:m_lights
|
||||||
|
lightPassFunc:lightPassFunc
|
||||||
|
totalAABB:m_totalAABB];
|
||||||
|
}
|
|
@ -0,0 +1,426 @@
|
||||||
|
#include "VISIRendererOpenGL.hpp"
|
||||||
|
#include "logvisor/logvisor.hpp"
|
||||||
|
#include "zeus/CFrustum.hpp"
|
||||||
|
|
||||||
|
static logvisor::Module Log("visigen");
|
||||||
|
|
||||||
|
static const char* VS =
|
||||||
|
"#version 330\n"
|
||||||
|
"layout(location=0) in vec4 posIn;\n"
|
||||||
|
"layout(location=1) in vec4 colorIn;\n"
|
||||||
|
"\n"
|
||||||
|
"uniform UniformBlock\n"
|
||||||
|
"{\n"
|
||||||
|
" mat4 xf;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"struct VertToFrag\n"
|
||||||
|
"{\n"
|
||||||
|
" vec4 color;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"out VertToFrag vtf;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" vtf.color = colorIn;\n"
|
||||||
|
" gl_Position = xf * vec4(posIn.xyz, 1.0);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
static const char* FS =
|
||||||
|
"#version 330\n"
|
||||||
|
"struct VertToFrag\n"
|
||||||
|
"{\n"
|
||||||
|
" vec4 color;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"in VertToFrag vtf;\n"
|
||||||
|
"layout(location=0) out vec4 colorOut;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" colorOut = vtf.color;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
static const uint32_t AABBIdxs[20] = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 1, 7, 3, 5, 5, 0, 0, 2, 6, 4};
|
||||||
|
|
||||||
|
static zeus::CMatrix4f g_Proj;
|
||||||
|
|
||||||
|
static void CalculateProjMatrix() {
|
||||||
|
float znear = 0.2f;
|
||||||
|
float zfar = 1000.f;
|
||||||
|
float tfov = std::tan(zeus::degToRad(90.f * 0.5f));
|
||||||
|
float top = znear * tfov;
|
||||||
|
float bottom = -top;
|
||||||
|
float right = znear * tfov;
|
||||||
|
float left = -right;
|
||||||
|
|
||||||
|
float rml = right - left;
|
||||||
|
float rpl = right + left;
|
||||||
|
float tmb = top - bottom;
|
||||||
|
float tpb = top + bottom;
|
||||||
|
float fpn = zfar + znear;
|
||||||
|
float fmn = zfar - znear;
|
||||||
|
|
||||||
|
g_Proj = zeus::CMatrix4f(2.f * znear / rml, 0.f, rpl / rml, 0.f, 0.f, 2.f * znear / tmb, tpb / tmb, 0.f, 0.f, 0.f,
|
||||||
|
-fpn / fmn, -2.f * zfar * znear / fmn, 0.f, 0.f, -1.f, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const zeus::CMatrix4f LookMATs[] = {
|
||||||
|
{// Forward
|
||||||
|
1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
||||||
|
{// Backward
|
||||||
|
-1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
||||||
|
{// Up
|
||||||
|
1.f, 0.f, 0.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
||||||
|
{// Down
|
||||||
|
1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
||||||
|
{// Left
|
||||||
|
0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
||||||
|
{// Right
|
||||||
|
0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f},
|
||||||
|
};
|
||||||
|
|
||||||
|
bool VISIRendererOpenGL::SetupShaders() {
|
||||||
|
CalculateProjMatrix();
|
||||||
|
|
||||||
|
if (glewInit() != GLEW_OK) {
|
||||||
|
Log.report(logvisor::Error, FMT_STRING("unable to init glew"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GLEW_ARB_occlusion_query2) {
|
||||||
|
Log.report(logvisor::Error, FMT_STRING("GL_ARB_occlusion_query2 extension not present"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_vtxShader = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
m_fragShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
m_program = glCreateProgram();
|
||||||
|
|
||||||
|
glShaderSource(m_vtxShader, 1, &VS, nullptr);
|
||||||
|
glCompileShader(m_vtxShader);
|
||||||
|
GLint status;
|
||||||
|
glGetShaderiv(m_vtxShader, GL_COMPILE_STATUS, &status);
|
||||||
|
if (status != GL_TRUE) {
|
||||||
|
GLint logLen;
|
||||||
|
glGetShaderiv(m_vtxShader, GL_INFO_LOG_LENGTH, &logLen);
|
||||||
|
char* log = (char*)malloc(logLen);
|
||||||
|
glGetShaderInfoLog(m_vtxShader, logLen, nullptr, log);
|
||||||
|
Log.report(logvisor::Error, FMT_STRING("unable to compile vert source\n{}\n{}\n"), log, VS);
|
||||||
|
free(log);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glShaderSource(m_fragShader, 1, &FS, nullptr);
|
||||||
|
glCompileShader(m_fragShader);
|
||||||
|
glGetShaderiv(m_fragShader, GL_COMPILE_STATUS, &status);
|
||||||
|
if (status != GL_TRUE) {
|
||||||
|
GLint logLen;
|
||||||
|
glGetShaderiv(m_fragShader, GL_INFO_LOG_LENGTH, &logLen);
|
||||||
|
char* log = (char*)malloc(logLen);
|
||||||
|
glGetShaderInfoLog(m_fragShader, logLen, nullptr, log);
|
||||||
|
Log.report(logvisor::Error, FMT_STRING("unable to compile frag source\n{}\n{}\n"), log, FS);
|
||||||
|
free(log);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glAttachShader(m_program, m_vtxShader);
|
||||||
|
glAttachShader(m_program, m_fragShader);
|
||||||
|
|
||||||
|
glLinkProgram(m_program);
|
||||||
|
glGetProgramiv(m_program, GL_LINK_STATUS, &status);
|
||||||
|
if (status != GL_TRUE) {
|
||||||
|
GLint logLen;
|
||||||
|
glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &logLen);
|
||||||
|
char* log = (char*)malloc(logLen);
|
||||||
|
glGetProgramInfoLog(m_program, logLen, nullptr, log);
|
||||||
|
Log.report(logvisor::Error, FMT_STRING("unable to link shader program\n{}\n"), log);
|
||||||
|
free(log);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glUseProgram(m_program);
|
||||||
|
m_uniLoc = glGetUniformBlockIndex(m_program, "UniformBlock");
|
||||||
|
|
||||||
|
glGenBuffers(1, &m_uniformBufferGL);
|
||||||
|
glBindBuffer(GL_UNIFORM_BUFFER, m_uniformBufferGL);
|
||||||
|
glBufferData(GL_UNIFORM_BUFFER, sizeof(zeus::CMatrix4f) * 6, nullptr, GL_DYNAMIC_DRAW);
|
||||||
|
|
||||||
|
glGenBuffers(1, &m_aabbIBO);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_aabbIBO);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 20 * 4, AABBIdxs, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glEnable(GL_PRIMITIVE_RESTART);
|
||||||
|
glPrimitiveRestartIndex(0xffffffff);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VISIRendererOpenGL::SetupVertexBuffersAndFormats() {
|
||||||
|
m_modelBindings.resize(m_models.size());
|
||||||
|
m_entityBindings.resize(m_entities.size());
|
||||||
|
m_lightBindings.resize(m_lights.size());
|
||||||
|
|
||||||
|
{
|
||||||
|
auto model = m_models.begin();
|
||||||
|
auto modelBinding = m_modelBindings.begin();
|
||||||
|
while (model != m_models.end()) {
|
||||||
|
glGenVertexArrays(1, &modelBinding->vao);
|
||||||
|
glGenBuffers(1, &modelBinding->vbo);
|
||||||
|
glGenBuffers(1, &modelBinding->ibo);
|
||||||
|
|
||||||
|
glBindVertexArray(modelBinding->vao);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, modelBinding->vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, model->verts.size() * sizeof(Model::Vert), model->verts.data(), GL_STATIC_DRAW);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(Model::Vert), 0);
|
||||||
|
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Model::Vert), (void*)16);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelBinding->ibo);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, model->idxs.size() * 4, model->idxs.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
++model;
|
||||||
|
++modelBinding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t idx = m_models.size();
|
||||||
|
{
|
||||||
|
auto ent = m_entities.begin();
|
||||||
|
auto entBinding = m_entityBindings.begin();
|
||||||
|
while (ent != m_entities.end()) {
|
||||||
|
glGenVertexArrays(1, &entBinding->vao);
|
||||||
|
glGenBuffers(1, &entBinding->vbo);
|
||||||
|
|
||||||
|
glBindVertexArray(entBinding->vao);
|
||||||
|
|
||||||
|
auto verts = AABBToVerts(ent->aabb, ColorForIndex(idx++));
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, entBinding->vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(Model::Vert), verts.data(), GL_STATIC_DRAW);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(Model::Vert), 0);
|
||||||
|
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Model::Vert), (void*)16);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_aabbIBO);
|
||||||
|
|
||||||
|
++ent;
|
||||||
|
++entBinding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto light = m_lights.begin();
|
||||||
|
auto lightBinding = m_lightBindings.begin();
|
||||||
|
while (light != m_lights.end()) {
|
||||||
|
glGenVertexArrays(1, &lightBinding->vao);
|
||||||
|
glGenBuffers(1, &lightBinding->vbo);
|
||||||
|
|
||||||
|
glBindVertexArray(lightBinding->vao);
|
||||||
|
|
||||||
|
Model::Vert vert;
|
||||||
|
vert.pos = light->point;
|
||||||
|
vert.color = ColorForIndex(idx++);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, lightBinding->vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(Model::Vert), &vert, GL_STATIC_DRAW);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(Model::Vert), 0);
|
||||||
|
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Model::Vert), (void*)16);
|
||||||
|
|
||||||
|
++light;
|
||||||
|
++lightBinding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_queryCount = m_models.size() + m_entities.size() + m_lights.size();
|
||||||
|
m_queries.reset(new GLuint[m_queryCount]);
|
||||||
|
m_queryBools.reset(new bool[m_queryCount]);
|
||||||
|
glGenQueries(GLsizei(m_queryCount), m_queries.get());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VISIRendererOpenGL::SetupRenderPass(const zeus::CVector3f& pos) {
|
||||||
|
glViewport(0, 0, 768, 512);
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glClearColor(0.f, 0.f, 0.f, 1.f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
std::array<std::aligned_union_t<256, zeus::CMatrix4f>, 6> m_uniformBuffers{};
|
||||||
|
static_assert(sizeof(m_uniformBuffers) == 256 * 6);
|
||||||
|
glBindBuffer(GL_UNIFORM_BUFFER, m_uniformBufferGL);
|
||||||
|
for (int j = 0; j < 6; ++j) {
|
||||||
|
zeus::CMatrix4f mv = LookMATs[j] * zeus::CTransform::Translate(-pos).toMatrix4f();
|
||||||
|
*static_cast<zeus::CMatrix4f*>(static_cast<void*>(&m_uniformBuffers[j])) = g_Proj * mv;
|
||||||
|
m_frustums[j].updatePlanes(mv, g_Proj);
|
||||||
|
}
|
||||||
|
glBufferData(GL_UNIFORM_BUFFER, sizeof(m_uniformBuffers), m_uniformBuffers.data(), GL_DYNAMIC_DRAW);
|
||||||
|
glUniformBlockBinding(m_program, m_uniLoc, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VISIRendererOpenGL::RenderPVSOpaque(RGBA8* bufOut, bool& needTransparent) {
|
||||||
|
for (int j = 0; j < 6; ++j) {
|
||||||
|
GLint x = (j % 3) * 256;
|
||||||
|
GLint y = (j / 3) * 256;
|
||||||
|
glViewport(x, y, 256, 256);
|
||||||
|
|
||||||
|
glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_uniformBufferGL, static_cast<GLintptr>(256 * j),
|
||||||
|
sizeof(zeus::CMatrix4f));
|
||||||
|
|
||||||
|
// Draw frontfaces
|
||||||
|
glCullFace(GL_BACK);
|
||||||
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||||
|
|
||||||
|
auto model = m_models.begin();
|
||||||
|
auto modelBinding = m_modelBindings.begin();
|
||||||
|
while (model != m_models.end()) {
|
||||||
|
if (m_frustums[j].aabbFrustumTest(model->aabb)) {
|
||||||
|
glBindVertexArray(modelBinding->vao);
|
||||||
|
for (const Model::Surface& surf : model->surfaces) {
|
||||||
|
// Non-transparents first
|
||||||
|
if (surf.transparent) {
|
||||||
|
needTransparent = true;
|
||||||
|
} else {
|
||||||
|
GLenum topology = model->topology == hecl::HMDLTopology::TriStrips ? GL_TRIANGLE_STRIP : GL_TRIANGLES;
|
||||||
|
glDrawElements(topology, surf.count, GL_UNSIGNED_INT, reinterpret_cast<void*>(uintptr_t(surf.first * 4)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++model;
|
||||||
|
++modelBinding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// m_swapFunc();
|
||||||
|
glFinish();
|
||||||
|
glReadPixels(0, 0, 768, 512, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)bufOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VISIRendererOpenGL::RenderPVSTransparent(const std::function<void(int)>& passFunc) {
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
for (int j = 0; j < 6; ++j) {
|
||||||
|
GLint x = (j % 3) * 256;
|
||||||
|
GLint y = (j / 3) * 256;
|
||||||
|
glViewport(x, y, 256, 256);
|
||||||
|
|
||||||
|
glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_uniformBufferGL, static_cast<GLintptr>(256 * j),
|
||||||
|
sizeof(zeus::CMatrix4f));
|
||||||
|
|
||||||
|
memset(m_queryBools.get(), 0, m_queryCount);
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
auto model = m_models.begin();
|
||||||
|
auto modelBinding = m_modelBindings.begin();
|
||||||
|
while (model != m_models.end()) {
|
||||||
|
if (m_frustums[j].aabbFrustumTest(model->aabb)) {
|
||||||
|
glBindVertexArray(modelBinding->vao);
|
||||||
|
glBeginQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, m_queries[idx]);
|
||||||
|
m_queryBools[idx] = true;
|
||||||
|
for (const Model::Surface& surf : model->surfaces) {
|
||||||
|
// transparents
|
||||||
|
if (surf.transparent) {
|
||||||
|
GLenum topology = model->topology == hecl::HMDLTopology::TriStrips ? GL_TRIANGLE_STRIP : GL_TRIANGLES;
|
||||||
|
glDrawElements(topology, surf.count, GL_UNSIGNED_INT, reinterpret_cast<void*>(uintptr_t(surf.first * 4)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glEndQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE);
|
||||||
|
}
|
||||||
|
++idx;
|
||||||
|
++model;
|
||||||
|
++modelBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < idx; ++i) {
|
||||||
|
if (m_queryBools[i]) {
|
||||||
|
GLint res;
|
||||||
|
glGetQueryObjectiv(m_queries[i], GL_QUERY_RESULT, &res);
|
||||||
|
if (res)
|
||||||
|
passFunc(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VISIRendererOpenGL::RenderPVSEntitiesAndLights(const std::function<void(int)>& passFunc,
|
||||||
|
const std::function<void(int, EPVSVisSetState)>& lightPassFunc) {
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
for (int j = 0; j < 6; ++j) {
|
||||||
|
GLint x = (j % 3) * 256;
|
||||||
|
GLint y = (j / 3) * 256;
|
||||||
|
glViewport(x, y, 256, 256);
|
||||||
|
|
||||||
|
glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_uniformBufferGL, static_cast<GLintptr>(256 * j),
|
||||||
|
sizeof(zeus::CMatrix4f));
|
||||||
|
|
||||||
|
memset(m_queryBools.get(), 0, m_queryCount);
|
||||||
|
|
||||||
|
uint32_t idx = m_models.size();
|
||||||
|
{
|
||||||
|
auto ent = m_entities.begin();
|
||||||
|
auto entBinding = m_entityBindings.begin();
|
||||||
|
while (ent != m_entities.end()) {
|
||||||
|
if (m_frustums[j].aabbFrustumTest(ent->aabb)) {
|
||||||
|
glBindVertexArray(entBinding->vao);
|
||||||
|
m_queryBools[idx] = true;
|
||||||
|
glBeginQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, m_queries[idx]);
|
||||||
|
glDrawElements(GL_TRIANGLE_STRIP, 20, GL_UNSIGNED_INT, 0);
|
||||||
|
glEndQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE);
|
||||||
|
}
|
||||||
|
++idx;
|
||||||
|
++ent;
|
||||||
|
++entBinding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto light = m_lights.begin();
|
||||||
|
auto lightBinding = m_lightBindings.begin();
|
||||||
|
while (light != m_lights.end()) {
|
||||||
|
if (m_frustums[j].pointFrustumTest(light->point)) {
|
||||||
|
glBindVertexArray(lightBinding->vao);
|
||||||
|
m_queryBools[idx] = true;
|
||||||
|
glBeginQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, m_queries[idx]);
|
||||||
|
glDrawArrays(GL_POINTS, 0, 1);
|
||||||
|
glEndQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE);
|
||||||
|
}
|
||||||
|
++idx;
|
||||||
|
++light;
|
||||||
|
++lightBinding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = m_models.size();
|
||||||
|
for (const Entity& ent : m_entities) {
|
||||||
|
(void)ent;
|
||||||
|
if (m_queryBools[idx]) {
|
||||||
|
GLint res;
|
||||||
|
glGetQueryObjectiv(m_queries[idx], GL_QUERY_RESULT, &res);
|
||||||
|
if (res)
|
||||||
|
passFunc(idx);
|
||||||
|
}
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lightIdx = 0;
|
||||||
|
for (const Light& light : m_lights) {
|
||||||
|
if (m_queryBools[idx]) {
|
||||||
|
GLint res;
|
||||||
|
glGetQueryObjectiv(m_queries[idx], GL_QUERY_RESULT, &res);
|
||||||
|
EPVSVisSetState state =
|
||||||
|
m_totalAABB.pointInside(light.point) ? EPVSVisSetState::EndOfTree : EPVSVisSetState::OutOfBounds;
|
||||||
|
if (res && state == EPVSVisSetState::EndOfTree)
|
||||||
|
state = EPVSVisSetState::NodeFound;
|
||||||
|
lightPassFunc(lightIdx, state);
|
||||||
|
}
|
||||||
|
++lightIdx;
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "VISIRenderer.hpp"
|
||||||
|
#include "boo/graphicsdev/glew.h"
|
||||||
|
|
||||||
|
#include <zeus/CFrustum.hpp>
|
||||||
|
|
||||||
|
class VISIRendererOpenGL : public VISIRenderer {
|
||||||
|
GLuint m_vtxShader, m_fragShader, m_program, m_uniLoc;
|
||||||
|
GLuint m_uniformBufferGL;
|
||||||
|
GLuint m_aabbIBO;
|
||||||
|
|
||||||
|
std::array<zeus::CFrustum, 6> m_frustums;
|
||||||
|
|
||||||
|
struct ModelBinding {
|
||||||
|
GLuint vbo, ibo, vao;
|
||||||
|
};
|
||||||
|
struct EntityBinding {
|
||||||
|
GLuint vbo, vao;
|
||||||
|
};
|
||||||
|
struct LightBinding {
|
||||||
|
GLuint vbo, vao;
|
||||||
|
};
|
||||||
|
std::vector<ModelBinding> m_modelBindings;
|
||||||
|
std::vector<EntityBinding> m_entityBindings;
|
||||||
|
std::vector<LightBinding> m_lightBindings;
|
||||||
|
|
||||||
|
size_t m_queryCount;
|
||||||
|
std::unique_ptr<GLuint[]> m_queries;
|
||||||
|
std::unique_ptr<bool[]> m_queryBools;
|
||||||
|
|
||||||
|
bool SetupShaders() override;
|
||||||
|
bool SetupVertexBuffersAndFormats() override;
|
||||||
|
void SetupRenderPass(const zeus::CVector3f& pos) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
VISIRendererOpenGL(int argc, const hecl::SystemChar** argv) : VISIRenderer(argc, argv) {}
|
||||||
|
void RenderPVSOpaque(RGBA8* bufOut, bool& needTransparent) override;
|
||||||
|
void RenderPVSTransparent(const std::function<void(int)>& passFunc) override;
|
||||||
|
void RenderPVSEntitiesAndLights(const std::function<void(int)>& passFunc,
|
||||||
|
const std::function<void(int, EPVSVisSetState)>& lightPassFunc) override;
|
||||||
|
};
|
Loading…
Reference in New Issue