Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions addons/godotvmf/entities/prop_static.gd
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,20 @@ var fade_max: float = 0.0:
get: return entity.get('fademaxdist', 0.0) * VMFConfig.import.scale

func _get_static_props_node() -> Node3D:
var geometry_node := get_vmfnode().geometry as MeshInstance3D;
if not geometry_node:
geometry_node = MeshInstance3D.new();
geometry_node.name = "Geometry";
get_vmfnode().add_child(geometry_node);
geometry_node.set_owner(get_vmfnode().owner);

if not model_instance: return;
var geometry_node := get_vmfnode().get_geometry_node();
var static_props_node := geometry_node.get_node_or_null("StaticProps");

if not static_props_node:
static_props_node = Node3D.new();
static_props_node.name = "StaticProps";
geometry_node.add_child(static_props_node);
static_props_node.set_owner(geometry_node.owner);

return static_props_node;

func assign_model_properties() -> void:
model_instance.set_owner(get_owner());
model_instance.scale *= model_scale;
model_instance.gi_mode = GeometryInstance3D.GI_MODE_STATIC;

var fade_margin = fade_max - fade_min;
Expand Down
14 changes: 14 additions & 0 deletions addons/godotvmf/entities/prop_studio.gd
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var skin: int = 0:
func _entity_setup(_entity: VMFEntity) -> void:
var model_path = VMFUtils.normalize_path(VMFConfig.models.target_folder + "/" + model);
var model_scene: PackedScene = VMFCache.get_cached(model);
var skin_prefix: String = entity.get("skin_prefix", "");

if not model_scene:
if not ResourceLoader.exists(model_path):
Expand All @@ -47,5 +48,18 @@ func _entity_setup(_entity: VMFEntity) -> void:

MDLCombiner.apply_skin(instance, skin);

if skin_prefix != "":
var surface_prefix: Array = skin_prefix.split(" ");

for surface_idx in range(instance.mesh.get_surface_count()):
var prefix := surface_prefix[surface_idx % surface_prefix.size()] as String;
if prefix == "": continue;

var material_path: String = instance.get_active_material(surface_idx).resource_path.replace(config.materials.target_folder + "/", "").get_basename();
var new_material_path: String = material_path + "_" + prefix;

instance.set_surface_override_material(surface_idx, VMTLoader.get_material(new_material_path));


add_child(instance);
model_instance.set_owner(get_owner());
3 changes: 3 additions & 0 deletions addons/godotvmf/src/structs/vmf_displacement_info.gd
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ func get_normal(x: float, y: float) -> Vector3:
if normals.size() == 0:
return Vector3.ZERO;

if index > normals.size() - 1:
return Vector3.ZERO;

return normals[index];

func get_offset(x: float, y: float) -> Vector3:
Expand Down
112 changes: 75 additions & 37 deletions addons/godotvmf/src/vmf_config.gd
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@ class_name VMFConfig extends RefCounted
const CONFIG_FILE_PATH = "res://vmf.config.json";

const SETTINGS_TO_LOAD = {
"godot_vmf/import/gameinfo_path": {
"godot_vmf/import/paths/gameinfo_path": {
"default_value": "res://",
"type": TYPE_STRING,
"hint": PROPERTY_HINT_GLOBAL_DIR,
},
"godot_vmf/import/paths/additional_import_paths": {
"default_value": [],
"type": TYPE_ARRAY,
"hint": PROPERTY_HINT_ARRAY_TYPE,
"hint_string": "%d/%d:" % [TYPE_STRING, PROPERTY_HINT_GLOBAL_DIR],
},
"godot_vmf/models/import": {
"default_value": false,
"type": TYPE_BOOL,
Expand Down Expand Up @@ -53,78 +59,97 @@ const SETTINGS_TO_LOAD = {
"type": TYPE_INT,
"hint": PROPERTY_HINT_NONE,
},
"godot_vmf/import/scale": {
"godot_vmf/import/general/scale": {
"default_value": 0.02,
"type": TYPE_FLOAT,
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0,100.0,0.000001",
},
"godot_vmf/import/generate_lightmap_uv2": {
"godot_vmf/import/general/generate_lightmap_uv2": {
"default_value": true,
"type": TYPE_BOOL,
"hint": PROPERTY_HINT_NONE,
},
"godot_vmf/import/generate_collision": {
"godot_vmf/import/general/generate_collision": {
"default_value": true,
"type": TYPE_BOOL,
"hint": PROPERTY_HINT_NONE,
},
"godot_vmf/import/generate_navigation_mesh": {
"godot_vmf/import/navmesh/enabled": {
"default_value": false,
"type": TYPE_BOOL,
"hint": PROPERTY_HINT_NONE,
},
"godot_vmf/import/navigation_mesh_preset": {
"godot_vmf/import/navmesh/preset": {
"default_value": "",
"type": TYPE_STRING,
"hint": PROPERTY_HINT_RESOURCE_TYPE,
"hint_string": "NavigationMesh",
},
"godot_vmf/import/lightmap_texel_size": {
"godot_vmf/import/general/lightmap_texel_size": {
"default_value": 0.2,
"type": TYPE_FLOAT,
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0,100.0,0.000001",
},
"godot_vmf/import/instances_folder": {
"godot_vmf/import/folders/instances": {
"default_value": "res://instances",
"type": TYPE_STRING,
"hint": PROPERTY_HINT_DIR,
},
"godot_vmf/import/entities_folder": {
"godot_vmf/import/folders/entities": {
"default_value": "res://entities",
"type": TYPE_STRING,
"hint": PROPERTY_HINT_DIR,
},
"godot_vmf/import/geometry_folder": {
"godot_vmf/import/folders/geometry": {
"default_value": "res://geometry",
"type": TYPE_STRING,
"hint": PROPERTY_HINT_DIR,
},
"godot_vmf/import/entity_aliases": {
"godot_vmf/import/general/entity_aliases": {
"default_value": {},
"type": TYPE_DICTIONARY,
"hint": PROPERTY_HINT_DICTIONARY_TYPE,
"hint_string": "%d:;%d/%d:*.tscn" % [TYPE_STRING, TYPE_STRING, PROPERTY_HINT_FILE],
},
"godot_vmf/import/detail_props_chunk_size": {
"godot_vmf/import/detail_props/chunk_size": {
"default_value": 32.0,
"type": TYPE_FLOAT,
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0,1000.0,0.000001",
},
"godot_vmf/import/detail_props_draw_distance": {
"godot_vmf/import/detail_props/draw_distance": {
"default_value": 100.0,
"type": TYPE_FLOAT,
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0,1000.0,0.000001",
},
"godot_vmf/import/additional_import_paths": {
"default_value": [],
"type": TYPE_ARRAY,
"hint": PROPERTY_HINT_ARRAY_TYPE,
"hint_string": "%d/%d:" % [TYPE_STRING, PROPERTY_HINT_GLOBAL_DIR],
}

"godot_vmf/import/chunked_mesh/default_chunk_size": {
"default_value": 256.0,
"description": "The size of the chunks that the level geometry will be split into. This is only used if chunked mesh feature is enabled.",
"type": TYPE_FLOAT,
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0,1024.0,0.01",
},
};

const SETTINGS_TO_REMAP = {
"godot_vmf/import/gameinfo_path": "godot_vmf/import/paths/gameinfo_path",
"godot_vmf/import/instances_folder": "godot_vmf/import/folders/instances",
"godot_vmf/import/entities_folder": "godot_vmf/import/folders/entities",
"godot_vmf/import/geometry_folder": "godot_vmf/import/folders/geometry",
"godot_vmf/import/navigation_mesh_preset": "godot_vmf/import/navmesh/preset",
"godot_vmf/import/detail_props_chunk_size": "godot_vmf/import/detail_props/chunk_size",
"godot_vmf/import/detail_props_draw_distance": "godot_vmf/import/detail_props/draw_distance",
"godot_vmf/import/chunked_mesh/chunk_size": "godot_vmf/import/chunked_mesh/default_chunk_size",
"godot_vmf/import/chunked_mesh/enabled": "", ## Will be removed during migration
"godot_vmf/import/scale": "godot_vmf/import/general/scale",
"godot_vmf/import/generate_lightmap_uv2": "godot_vmf/import/general/generate_lightmap_uv2",
"godot_vmf/import/generate_collision": "godot_vmf/import/general/generate_collision",
"godot_vmf/import/lightmap_texel_size": "godot_vmf/import/general/lightmap_texel_size",
"godot_vmf/import/entity_aliases": "godot_vmf/import/general/entity_aliases",
};

class ModelsConfig:
Expand Down Expand Up @@ -166,55 +191,56 @@ class MaterialsConfig:

class ImportConfig:
## Target scale that will be applied to all imported models and maps
var scale: float = ProjectSettings.get_setting("godot_vmf/import/scale", 0.02);
var scale: float = ProjectSettings.get_setting("godot_vmf/import/general/scale", 0.02);

## If true, the importer will generate collision meshes for the level geometry
var generate_collision: bool = ProjectSettings.get_setting("godot_vmf/import/generate_collision", true);
var generate_collision: bool = ProjectSettings.get_setting("godot_vmf/import/general/generate_collision", true);

## If true, the importer will generate lightmap UV2 for the level geometry
var generate_lightmap_uv2: bool = ProjectSettings.get_setting("godot_vmf/import/generate_lightmap_uv2", true);
var generate_lightmap_uv2: bool = ProjectSettings.get_setting("godot_vmf/import/general/generate_lightmap_uv2", true);

## Texel size for lightmap
var lightmap_texel_size: float = ProjectSettings.get_setting("godot_vmf/import/lightmap_texel_size", 0.2);
var lightmap_texel_size: float = ProjectSettings.get_setting("godot_vmf/import/general/lightmap_texel_size", 0.2);

## Lightmap texture size
var lightmap_size: int = ProjectSettings.get_setting("godot_vmf/import/lightmap_size", 1024);

## The path where imported instances be saved
var instances_folder: String = ProjectSettings.get_setting("godot_vmf/import/instances_folder", "res://instances");
var instances_folder: String = ProjectSettings.get_setting("godot_vmf/import/folders/instances", "res://instances");

## The path from importer will grab entities
var entities_folder: String = ProjectSettings.get_setting("godot_vmf/import/entities_folder", "res://entities");
## The path the importer will grab entities from during import
var entities_folder: String = ProjectSettings.get_setting("godot_vmf/import/folders/entities", "res://entities");

## The path where imported geometry and collision be saved
var geometry_folder: String = ProjectSettings.get_setting("godot_vmf/import/geometry_folder", "res://geometry");
var geometry_folder: String = ProjectSettings.get_setting("godot_vmf/import/folders/geometry", "res://geometry");

## A dictionary of entity aliases where key is an entity name and value is a path to the scene
var entity_aliases: Dictionary = ProjectSettings.get_setting("godot_vmf/import/entity_aliases", {}):
var entity_aliases: Dictionary = ProjectSettings.get_setting("godot_vmf/import/general/entity_aliases", {}):
set(value):
ProjectSettings.set_setting("godot_vmf/entity_aliases", value);

## If true, the importer will generate a navigation mesh for the level geometry
var use_navigation_mesh: bool = ProjectSettings.get_setting("godot_vmf/import/generate_navigation_mesh", false);
var use_navigation_mesh: bool = ProjectSettings.get_setting("godot_vmf/import/navmesh/enabled", false);

## If specified, the importer will use this preset for the navigation mesh
var navigation_mesh_preset: String = ProjectSettings.get_setting("godot_vmf/import/navigation_mesh_preset", "");
var navigation_mesh_preset: String = ProjectSettings.get_setting("godot_vmf/import/navmesh/preset", "");

## Detail props are meshes instanced across the level geometry based on material metadata.
## This field defines a size of one chunk of detail props. The bigger the chunk size, the less multimesh instances will be created,
## but the more detail props will be in one chunk, which can lead to worse performance.
var detail_props_chunk_size: float = ProjectSettings.get_setting("godot_vmf/import/detail_props_chunk_size", 32.0);
var detail_props_chunk_size: float = ProjectSettings.get_setting("godot_vmf/import/detail_props/chunk_size", 32.0);

## The maximum distance at which detail props will be visible. This is important for performance, as rendering too many detail props at long distances can be costly.
var detail_props_draw_distance: float = ProjectSettings.get_setting("godot_vmf/import/detail_props_draw_distance", 100.0);

var gameinfo_path: String = ProjectSettings.get_setting("godot_vmf/import/gameinfo_path", "res://");
var detail_props_draw_distance: float = ProjectSettings.get_setting("godot_vmf/import/detail_props/draw_distance", 100.0);

var gameinfo_path: String = ProjectSettings.get_setting("godot_vmf/import/paths/gameinfo_path", "res://")
var additional_import_paths: Array = ProjectSettings.get_setting("godot_vmf/import/additional_import_paths", []);

var chunked_mesh_default_size: float = ProjectSettings.get_setting("godot_vmf/import/chunked_mesh/default_chunk_size", 256.0);

## NOTE: Support previous version of this config where this field wasn't a part of ImportConfig
static var gameinfo_path: String:
get: return ProjectSettings.get_setting("godot_vmf/import/gameinfo_path", "res://");
get: return import.gameinfo_path

static var models: ModelsConfig:
get:
Expand Down Expand Up @@ -257,8 +283,6 @@ static func is_dictionary_equal(a: Dictionary, b: Dictionary):
return true;

static func update_config_field():
gameinfo_path = ProjectSettings.get_setting("godot_vmf/import/gameinfo_path", "res://");

import = ImportConfig.new();
models = ModelsConfig.new();
materials = MaterialsConfig.new();
Expand All @@ -283,10 +307,24 @@ static func define_project_settings():

static func load_config():
if not Engine.is_editor_hint(): return;
remap_old_settings();

if not FileAccess.file_exists(CONFIG_FILE_PATH): return;
var file = FileAccess.open(CONFIG_FILE_PATH, FileAccess.READ);
var json = JSON.parse_string(file.get_as_text());
file.close();

assign(VMFConfig, json);
update_config_field();

## Remap old settings to new settings if they exist in the project settings
static func remap_old_settings():
for old_setting in SETTINGS_TO_REMAP:
if ProjectSettings.has_setting(old_setting):
var new_setting = SETTINGS_TO_REMAP[old_setting];
if new_setting == "":
ProjectSettings.set_setting(old_setting, null);
continue;
var value = ProjectSettings.get_setting(old_setting);
ProjectSettings.set_setting(new_setting, value);
ProjectSettings.set_setting(old_setting, null);
Loading