more agony (oversight fixes and dreamcast build works again (although it doesn't resolve my outstanding issues of too large of a scene mesh......))
This commit is contained in:
parent
bc406d5b62
commit
eadf732ee5
3
Makefile
3
Makefile
@ -313,7 +313,8 @@ $(EXT_EX_DLL): $(OBJS_EXT_DLL)
|
||||
|
||||
$(TARGET): $(OBJS) #./bin/dreamcast/romdisk.o
|
||||
$(CXX) $(FLAGS) $(INCS) -D_arch_dreamcast -D_arch_sub_pristine -Wall -fno-builtin -ml -Wl,-Ttext=0x8c010000 -T/opt/dreamcast/kos/utils/ldscripts/shlelf.xc -nodefaultlibs $(KOS_LIB_PATHS) $(LIBS) -o $(TARGET) $(OBJS) -Wl,--start-group $(DEPS) -Wl,--end-group
|
||||
$(KOS_STRIP) --strip-unneeded $(TARGET)
|
||||
cp $(TARGET) $(TARGET).unstripped
|
||||
$(KOS_STRIP) --strip-unneeded $(TARGET)
|
||||
|
||||
./bin/dreamcast/$(TARGET_NAME).cdi: $(TARGET)
|
||||
cd ./bin/dreamcast/; ./elf2cdi.sh $(TARGET_NAME)
|
||||
|
@ -79,7 +79,7 @@
|
||||
"tag": "worldspawn",
|
||||
"player": "info_player_spawn",
|
||||
"enabled": "auto",
|
||||
"radius": 32,
|
||||
"radius": 16,
|
||||
"every": 4
|
||||
}
|
||||
}
|
||||
|
@ -11,12 +11,12 @@
|
||||
// exact matches
|
||||
"worldspawn": {
|
||||
"physics": { "type": "mesh", "static": true },
|
||||
"grid": { "size": [8,1,8], "epsilon": 0.001, "cleanup": true, "print": true },
|
||||
"grid": { "size": [16,1,16], "epsilon": 0.001, "cleanup": true, "print": true, "clip": true },
|
||||
"optimize meshlets": { "simplify": 0.125, "print": false },
|
||||
"unwrap mesh": true
|
||||
},
|
||||
"worldspawn_skybox": {
|
||||
"grid": { "size": [8,1,8], "epsilon": 0.001, "cleanup": true, "print": true },
|
||||
"grid": { "size": [16,1,16], "epsilon": 0.001, "cleanup": true, "print": true, "clip": true },
|
||||
"optimize meshlets": { "simplify": 0.125, "print": false },
|
||||
"unwrap mesh": true
|
||||
},
|
||||
|
@ -1 +1 @@
|
||||
opengl
|
||||
vulkan
|
@ -58,12 +58,8 @@
|
||||
#define GL_SILENCE_DEPRECATION
|
||||
#include <OpenGL/gl.h>
|
||||
#else
|
||||
#if UF_ENV_DREAMCAST
|
||||
#include <GLdc/gl.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct ImGui_ImplOpenGL2_Data
|
||||
{
|
||||
|
@ -317,6 +317,9 @@ namespace uf {
|
||||
size_t bytes = elements * sizeof(To);
|
||||
|
||||
auto& srcBuffer = this->buffers[attribute.buffer];
|
||||
|
||||
if ( srcBuffer.empty() ) continue;
|
||||
|
||||
uf::stl::vector<uint8_t> dstBuffer( srcBuffer.size() * scale );
|
||||
|
||||
attribute.pointer = (uint8_t*) dstBuffer.data();
|
||||
|
@ -16,6 +16,8 @@
|
||||
#define UF_GRAPH_LOAD_MULTITHREAD 0
|
||||
#endif
|
||||
|
||||
#define UF_GRAPH_EXTENDED 1
|
||||
|
||||
#if 0 && UF_ENV_DREAMCAST
|
||||
#define UF_DEBUG_TIMER_MULTITRACE_START(...) UF_TIMER_MULTITRACE_START(__VA_ARGS__)
|
||||
#define UF_DEBUG_TIMER_MULTITRACE(...) UF_TIMER_MULTITRACE(__VA_ARGS__)
|
||||
@ -238,6 +240,9 @@ namespace {
|
||||
const uf::stl::string filename = value.as<uf::stl::string>();
|
||||
const uf::stl::string directory = uf::io::directory( graph.name );
|
||||
// uf::io::readAsBuffer( directory + "/" + filename )
|
||||
#if !UF_GRAPH_EXTENDED
|
||||
mesh.buffers.emplace_back(uf::io::readAsBuffer( directory + "/" + filename ));
|
||||
#else
|
||||
if ( graph.metadata["stream"]["enabled"].as<bool>() ) {
|
||||
mesh.buffers.emplace_back();
|
||||
mesh.buffer_paths.emplace_back(directory + "/" + filename );
|
||||
@ -245,6 +250,7 @@ namespace {
|
||||
// to-do: make it work for interleaved meshes
|
||||
mesh.buffers.emplace_back(uf::io::readAsBuffer( directory + "/" + filename ));
|
||||
}
|
||||
#endif
|
||||
});
|
||||
|
||||
// load non vertex/index buffers
|
||||
@ -261,7 +267,8 @@ namespace {
|
||||
|
||||
#if UF_ENV_DREAMCAST
|
||||
// remove extraneous buffers
|
||||
if ( graph.metadata["renderer"]["separate"].as<bool>() ) {
|
||||
// if ( graph.metadata["renderer"]["separate"].as<bool>() )
|
||||
{
|
||||
uf::stl::vector<uf::stl::string> attributesKept = ext::json::vector<uf::stl::string>(graph.metadata["decode"]["attributes"]);
|
||||
if ( !mesh.isInterleaved() ) {
|
||||
uf::stl::vector<size_t> remove; remove.reserve(mesh.vertex.attributes.size());
|
||||
@ -283,9 +290,8 @@ namespace {
|
||||
}
|
||||
#endif
|
||||
|
||||
mesh.updateDescriptor();
|
||||
#if 0
|
||||
if ( graph.metadata["renderer"]["separate"].as<bool>() ) {
|
||||
// if ( graph.metadata["renderer"]["separate"].as<bool>() )
|
||||
{
|
||||
#if UF_ENV_DREAMCAST && GL_QUANTIZED_SHORT
|
||||
mesh.convert<float, uint16_t>();
|
||||
UF_MSG_DEBUG("Quantizing mesh to GL_QUANTIZED_SHORT");
|
||||
@ -306,7 +312,6 @@ namespace {
|
||||
#endif
|
||||
mesh.updateDescriptor();
|
||||
}
|
||||
#endif
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
@ -17,13 +17,19 @@
|
||||
#define UF_DEBUG_TIMER_MULTITRACE_START(...) UF_TIMER_MULTITRACE_START(__VA_ARGS__)
|
||||
#define UF_DEBUG_TIMER_MULTITRACE(...) UF_TIMER_MULTITRACE(__VA_ARGS__)
|
||||
#define UF_DEBUG_TIMER_MULTITRACE_END(...) UF_TIMER_MULTITRACE_END(__VA_ARGS__)
|
||||
#define UF_GRAPH_SPARSE_READ_MESH 1
|
||||
#else
|
||||
#define UF_DEBUG_TIMER_MULTITRACE_START(...)
|
||||
#define UF_DEBUG_TIMER_MULTITRACE(...)
|
||||
#define UF_DEBUG_TIMER_MULTITRACE_END(...)
|
||||
#if UF_USE_OPENGL
|
||||
#define UF_GRAPH_SPARSE_READ_MESH 1
|
||||
#else
|
||||
#define UF_GRAPH_SPARSE_READ_MESH 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define UF_GRAPH_SPARSE_READ_MESH 1
|
||||
#define UF_GRAPH_EXTENDED 1
|
||||
|
||||
namespace {
|
||||
bool newGraphAdded = true;
|
||||
@ -1230,7 +1236,9 @@ void uf::graph::process( pod::Graph& graph ) {
|
||||
}
|
||||
|
||||
UF_DEBUG_TIMER_MULTITRACE("Updating master graph");
|
||||
#if UF_GRAPH_EXTENDED
|
||||
uf::graph::reload( graph );
|
||||
#endif
|
||||
uf::graph::reload();
|
||||
|
||||
storage.instanceAddresses.keys = storage.instances.keys;
|
||||
@ -1412,6 +1420,74 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
|
||||
storage.entities[objectKeyName] = &entity;
|
||||
|
||||
//
|
||||
#if !UF_GRAPH_EXTENDED
|
||||
if ( 0 <= node.mesh && node.mesh < graph.meshes.size() ) {
|
||||
auto model = uf::transform::model( transform );
|
||||
auto& mesh = storage.meshes.map[graph.meshes[node.mesh]];
|
||||
auto& primitives = storage.primitives.map[graph.primitives[node.mesh]];
|
||||
|
||||
pod::Instance::Bounds bounds;
|
||||
// setup instances
|
||||
for ( auto i = 0; i < primitives.size(); ++i ) {
|
||||
auto& primitive = primitives[i];
|
||||
|
||||
size_t instanceID = storage.instances.keys.size();
|
||||
auto instanceKeyName = graph.instances.emplace_back(std::to_string(instanceID));
|
||||
|
||||
auto& instance = storage.instances[instanceKeyName];
|
||||
instance = primitive.instance;
|
||||
|
||||
instance.model = model;
|
||||
instance.previous = model;
|
||||
instance.objectID = objectID;
|
||||
instance.jointID = graph.metadata["renderer"]["skinned"].as<bool>() ? 0 : -1;
|
||||
|
||||
bounds.min = uf::vector::min( bounds.min, instance.bounds.min );
|
||||
bounds.max = uf::vector::max( bounds.max, instance.bounds.max );
|
||||
|
||||
if ( mesh.indirect.count && mesh.indirect.count <= primitives.size() ) {
|
||||
auto& attribute = mesh.indirect.attributes.front();
|
||||
auto& buffer = mesh.buffers[mesh.isInterleaved(mesh.indirect.interleaved) ? mesh.indirect.interleaved : attribute.buffer];
|
||||
pod::DrawCommand* drawCommands = (pod::DrawCommand*) buffer.data();
|
||||
auto& drawCommand = drawCommands[i];
|
||||
drawCommand.instanceID = instanceID;
|
||||
}
|
||||
}
|
||||
if ( /*(graph.metadata["renderer"]["separate"].as<bool>()) &&*/ graph.metadata["renderer"]["render"].as<bool>() ) {
|
||||
uf::graph::initializeGraphics( graph, entity, mesh );
|
||||
}
|
||||
|
||||
{
|
||||
auto phyziks = tag["physics"];
|
||||
if ( !ext::json::isObject( phyziks ) ) phyziks = metadataJson["physics"];
|
||||
else metadataJson["physics"] = phyziks;
|
||||
|
||||
if ( ext::json::isObject( phyziks ) ) {
|
||||
uf::stl::string type = phyziks["type"].as<uf::stl::string>();
|
||||
|
||||
if ( type == "mesh" ) {
|
||||
auto& collider = entity.getComponent<pod::PhysicsState>();
|
||||
collider.stats.mass = phyziks["mass"].as(collider.stats.mass);
|
||||
collider.stats.friction = phyziks["friction"].as(collider.stats.friction);
|
||||
collider.stats.restitution = phyziks["restitution"].as(collider.stats.restitution);
|
||||
collider.stats.inertia = uf::vector::decode( phyziks["inertia"], collider.stats.inertia );
|
||||
collider.stats.gravity = uf::vector::decode( phyziks["gravity"], collider.stats.gravity );
|
||||
|
||||
uf::physics::impl::create( entity.as<uf::Object>(), mesh, !phyziks["static"].as<bool>(true) );
|
||||
} else {
|
||||
auto min = uf::matrix::multiply<float>( model, bounds.min, 1.0f );
|
||||
auto max = uf::matrix::multiply<float>( model, bounds.max, 1.0f );
|
||||
|
||||
pod::Vector3f center = (max + min) * 0.5f;
|
||||
pod::Vector3f corner = uf::vector::abs(max - min) * 0.5f;
|
||||
|
||||
metadataJson["physics"]["center"] = uf::vector::encode( center );
|
||||
metadataJson["physics"]["corner"] = uf::vector::encode( corner );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if ( 0 <= node.mesh && node.mesh < graph.meshes.size() ) {
|
||||
auto model = uf::transform::model( transform );
|
||||
auto& mesh = storage.meshes.map[graph.meshes[node.mesh]];
|
||||
@ -1467,6 +1543,7 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for ( auto index : node.children ) uf::graph::process( graph, index, entity );
|
||||
}
|
||||
@ -1555,10 +1632,12 @@ void uf::graph::update( pod::Graph& graph, float delta ) {
|
||||
auto& storage = uf::graph::globalStorage ? uf::graph::storage : scene.getComponent<pod::Graph::Storage>();
|
||||
|
||||
// get last update time
|
||||
#if UF_GRAPH_EXTENDED
|
||||
if ( graph.settings.stream.enabled && graph.settings.stream.hash != 0 && uf::physics::time::current - graph.settings.stream.lastUpdate > graph.settings.stream.every ) {
|
||||
graph.settings.stream.lastUpdate = uf::physics::time::current;
|
||||
uf::graph::reload( graph );
|
||||
}
|
||||
#endif
|
||||
|
||||
// update our instances
|
||||
#if !UF_ENV_DREAMCAST
|
||||
@ -1702,14 +1781,14 @@ void uf::graph::tick( pod::Graph::Storage& storage ) {
|
||||
*/
|
||||
bool rebuild = false;
|
||||
uf::stl::vector<pod::Instance> instances = storage.instances.flatten();
|
||||
rebuild = rebuild || storage.buffers.instance.update( (const void*) instances.data(), instances.size() * sizeof(pod::Instance) );
|
||||
rebuild = storage.buffers.instance.update( (const void*) instances.data(), instances.size() * sizeof(pod::Instance) ) || rebuild;
|
||||
/*
|
||||
uf::stl::vector<pod::Instance::Addresses> instanceAddresses; instanceAddresses.reserve(storage.instanceAddresses.map.size());
|
||||
for ( auto& key : storage.instances.keys ) instanceAddresses.emplace_back( storage.instanceAddresses.map[key] );
|
||||
if ( !instanceAddresses.empty() ) rebuild = rebuild || storage.buffers.instanceAddresses.update( (const void*) instanceAddresses.data(), instanceAddresses.size() * sizeof(pod::Instance::Addresses) );
|
||||
if ( !instanceAddresses.empty() ) rebuild = storage.buffers.instanceAddresses.update( (const void*) instanceAddresses.data(), instanceAddresses.size() * sizeof(pod::Instance::Addresses) ) || rebuild;
|
||||
*/
|
||||
uf::stl::vector<pod::Instance::Addresses> instanceAddresses = storage.instanceAddresses.flatten();
|
||||
rebuild = rebuild || storage.buffers.instanceAddresses.update( (const void*) instanceAddresses.data(), instanceAddresses.size() * sizeof(pod::Instance::Addresses) );
|
||||
rebuild = storage.buffers.instanceAddresses.update( (const void*) instanceAddresses.data(), instanceAddresses.size() * sizeof(pod::Instance::Addresses) ) || rebuild;
|
||||
|
||||
uf::stl::vector<pod::Matrix4f> joints; joints.reserve(storage.joints.map.size());
|
||||
for ( auto& key : storage.joints.keys ) {
|
||||
@ -1717,7 +1796,7 @@ void uf::graph::tick( pod::Graph::Storage& storage ) {
|
||||
joints.reserve( joints.size() + matrices.size() );
|
||||
for ( auto& mat : matrices ) joints.emplace_back( mat );
|
||||
}
|
||||
/*if ( !joints.empty() )*/ rebuild = rebuild || storage.buffers.joint.update( (const void*) joints.data(), joints.size() * sizeof(pod::Matrix4f) );
|
||||
/*if ( !joints.empty() )*/ rebuild = storage.buffers.joint.update( (const void*) joints.data(), joints.size() * sizeof(pod::Matrix4f) ) || rebuild;
|
||||
|
||||
if ( ::newGraphAdded ) {
|
||||
#if 1
|
||||
@ -1735,9 +1814,9 @@ void uf::graph::tick( pod::Graph::Storage& storage ) {
|
||||
for ( auto& key : storage.materials.keys ) materials.emplace_back( storage.materials.map[key] );
|
||||
for ( auto& key : storage.textures.keys ) textures.emplace_back( storage.textures.map[key] );
|
||||
#endif
|
||||
rebuild = rebuild || storage.buffers.drawCommands.update( (const void*) drawCommands.data(), drawCommands.size() * sizeof(pod::DrawCommand) );
|
||||
rebuild = rebuild || storage.buffers.material.update( (const void*) materials.data(), materials.size() * sizeof(pod::Material) );
|
||||
rebuild = rebuild || storage.buffers.texture.update( (const void*) textures.data(), textures.size() * sizeof(pod::Texture) );
|
||||
rebuild = storage.buffers.drawCommands.update( (const void*) drawCommands.data(), drawCommands.size() * sizeof(pod::DrawCommand) ) || rebuild;
|
||||
rebuild = storage.buffers.material.update( (const void*) materials.data(), materials.size() * sizeof(pod::Material) ) || rebuild;
|
||||
rebuild = storage.buffers.texture.update( (const void*) textures.data(), textures.size() * sizeof(pod::Texture) ) || rebuild;
|
||||
|
||||
::newGraphAdded = false;
|
||||
|
||||
@ -1918,6 +1997,10 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) {
|
||||
radius = 0;
|
||||
}
|
||||
|
||||
if ( mesh.buffer_paths.empty() ) {
|
||||
radius = 0;
|
||||
}
|
||||
|
||||
if ( radius > 0 && mesh.indirect.count && mesh.indirect.count <= primitives.size() ) {
|
||||
// deduce draw command (indirect) buffer to write to
|
||||
auto& attribute = mesh.indirect.attributes.front();
|
||||
@ -2051,24 +2134,28 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) {
|
||||
} else {
|
||||
// load mesh data
|
||||
for ( auto& attribute : mesh.index.attributes ) {
|
||||
if ( mesh.buffers[attribute.buffer].empty() ) mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer] );
|
||||
if ( !mesh.buffers[attribute.buffer].empty() || mesh.buffer_paths.empty() ) continue;
|
||||
mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer] );
|
||||
}
|
||||
for ( auto& attribute : mesh.vertex.attributes ) {
|
||||
if ( mesh.buffers[attribute.buffer].empty() ) mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer] );
|
||||
if ( !mesh.buffers[attribute.buffer].empty() || mesh.buffer_paths.empty() ) continue;
|
||||
mesh.buffers[attribute.buffer] = uf::io::readAsBuffer( mesh.buffer_paths[attribute.buffer] );
|
||||
}
|
||||
}
|
||||
|
||||
mesh.updateDescriptor();
|
||||
|
||||
// process textures
|
||||
|
||||
// update graphic
|
||||
#if 0
|
||||
if ( (graph.metadata["renderer"]["separate"].as<bool>()) && graph.metadata["renderer"]["render"].as<bool>() ) {
|
||||
#endif
|
||||
if ( graph.metadata["renderer"]["render"].as<bool>() ) {
|
||||
if ( /*(graph.metadata["renderer"]["separate"].as<bool>()) &&*/ graph.metadata["renderer"]["render"].as<bool>() ) {
|
||||
bool exists = entity.hasComponent<uf::renderer::Graphic>();
|
||||
if ( exists ) {
|
||||
auto& graphic = entity.getComponent<uf::renderer::Graphic>();
|
||||
graphic.updateMesh( mesh );
|
||||
bool rebuild = graphic.updateMesh( mesh );
|
||||
if ( rebuild ) {
|
||||
// uf::renderer::states::rebuild = true;
|
||||
}
|
||||
} else {
|
||||
uf::graph::initializeGraphics( graph, entity, mesh );
|
||||
}
|
||||
|
@ -566,6 +566,14 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize
|
||||
// disable lightmap loading, 99.999% of the time a previously baked lightmap will not work due to changing STs
|
||||
graph.metadata["lights"]["lightmapped"] = false;
|
||||
}
|
||||
|
||||
// disable streaming
|
||||
{
|
||||
graph.settings.stream.enabled = false;
|
||||
graph.settings.stream.radius = 0;
|
||||
graph.settings.stream.every = 0;
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
#endif
|
@ -378,7 +378,6 @@ if ( meshopt.should ) {
|
||||
mesh.bindIndirect<pod::DrawCommand>();
|
||||
mesh.bind<UF_GRAPH_MESH_FORMAT>(false); // default to de-interleaved regardless of requirement (makes things easier)
|
||||
|
||||
UF_MSG_DEBUG("{}: {}", keyName, meshlets.size() );
|
||||
for ( auto& meshlet : meshlets ) {
|
||||
auto& drawCommand = drawCommands.emplace_back(pod::DrawCommand{
|
||||
.indices = meshlet.indices.size(),
|
||||
|
@ -186,12 +186,24 @@ bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool st
|
||||
// if ( !data || !length ) return false;
|
||||
if ( !length ) return false;
|
||||
if ( !buffer ) return false;
|
||||
if ( length > allocationInfo.size ) {
|
||||
UF_MSG_WARNING("Buffer update of {} exceeds buffer size of {}", length, allocationInfo.size );
|
||||
|
||||
Buffer& b = *const_cast<Buffer*>(this);
|
||||
b.destroy(true);
|
||||
b.initialize( data, length, usage, memoryProperties, stage );
|
||||
// to-do: fix this because it's a thorn in my side when a mesh needs to update
|
||||
if ( length > allocationInfo.size ) {
|
||||
UF_MSG_WARNING("Buffer update of {} exceeds buffer size of {}", length, allocationInfo.size);
|
||||
|
||||
auto savedUsage = usage;
|
||||
auto savedMemProps = memoryProperties;
|
||||
auto savedAlignment = alignment;
|
||||
|
||||
Buffer& oldBuffer = *const_cast<Buffer*>(this);
|
||||
Buffer newBuffer = {};
|
||||
|
||||
oldBuffer.swap(newBuffer);
|
||||
newBuffer.destroy(true);
|
||||
|
||||
oldBuffer.initialize(*device, savedAlignment);
|
||||
oldBuffer.initialize(data, length, savedUsage, savedMemProps, stage);
|
||||
|
||||
return true;
|
||||
}
|
||||
if ( !data ) return false;
|
||||
|
@ -4,7 +4,7 @@ CC = gcc
|
||||
CXX = $(KOS_CCPLUS)
|
||||
RENDERER = opengl
|
||||
TARGET_EXTENSION = elf
|
||||
OPTIMIZATIONS = -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -fstrict-aliasing -ffast-math -fno-unroll-all-loops -fno-optimize-sibling-calls -fschedule-insns2 -fomit-frame-pointer -DUF_NO_EXCEPTIONS -fno-exceptions -flto # -g
|
||||
OPTIMIZATIONS = -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -fstrict-aliasing -ffast-math -fno-unroll-all-loops -fno-optimize-sibling-calls -fschedule-insns2 -fomit-frame-pointer -DUF_NO_EXCEPTIONS -fno-exceptions -flto -g
|
||||
WARNINGS = -Wno-attributes -Wno-conversion-null
|
||||
FLAGS += $(KOS_CPPFLAGS) -m4-single -std=c++17 $(OPTIMIZATIONS) $(WARNINGS) -fdiagnostics-color=always
|
||||
INCS += $(KOS_INC_PATHS) -I/opt/dreamcast/sh-elf/sh-elf/include
|
||||
|
Loading…
Reference in New Issue
Block a user