extends Node class ObjectManager: var GIANTS_PATH = "/home/tasty/Jeux/Giants Citizen Kabuto" var index = {} func build() -> void: var bin_dir = Directory.new() if bin_dir.open(GIANTS_PATH+"/Bin") == OK: bin_dir.list_dir_begin() var file_name = bin_dir.get_next() while (file_name != ""): if not bin_dir.current_is_dir() and file_name.ends_with(".gzp"): # print("Found GZP file: " + file_name) var gzp_file = File.new() gzp_file.open(GIANTS_PATH+"/Bin/"+file_name, File.READ) read_gzp_to_indexes(gzp_file) gzp_file.close() file_name = bin_dir.get_next() func read_gzp_to_indexes(file: File) -> void: var checksum = file.get_32() assert(checksum == 0x6608F101) var meta_info_offset = file.get_32() file.seek(meta_info_offset) var _unk = file.get_32() var entries_count = file.get_32() for _i in range(entries_count): var _compressed_size = file.get_32() var _original_size = file.get_32() var _file_time = file.get_32() var _content_offset = file.get_32() + 16 var _compression = file.get_8() var name_length = file.get_8() var name = file.get_buffer(name_length).get_string_from_ascii() name = name.to_lower() if name.ends_with(".tga") or name.ends_with(".gbs"): index[name] = file.get_path_absolute() func read_file_in_gzp(filename: String) -> StreamPeerBuffer: filename = filename.to_lower() if not filename in index: return null var gzp_file = index[filename] var res = StreamPeerBuffer.new() var file = File.new() if not file.open(gzp_file, File.READ) == OK: print("Could not open "+gzp_file) return res var checksum = file.get_32() assert(checksum == 0x6608F101) var meta_info_offset = file.get_32() file.seek(meta_info_offset) var _unk = file.get_32() var entries_count = file.get_32() for _i in range(entries_count): var compressed_size = file.get_32() var original_size = file.get_32() var _file_time = file.get_32() var content_offset = file.get_32() + 16 var compression = file.get_8() var name_length = file.get_8() var name = file.get_buffer(name_length).get_string_from_ascii() if name.to_lower() == filename: var current_offset = file.get_position() file.seek(content_offset) var data = file.get_buffer(compressed_size) file.seek(current_offset) if compression == 1: data = _decompress(data, original_size) res.data_array = data file.close() if res.data_array.size() == 0: print("Could not open "+filename) return null return res func load_model(gbs_file: String): gbs_file = gbs_file.to_lower() var gbs_stream = read_file_in_gzp(gbs_file) if not gbs_stream: return null var model = load("res://model.gd").Model.new() var modelitem_gd = load("res://modelitem.gd") model.magic = gbs_stream.get_32() model.u1 = gbs_stream.get_32() model.basepoints = gbs_stream.get_32() model.basepoint = [] model.basepoint.resize(model.basepoints) for s in range(model.basepoints): var x = gbs_stream.get_float() var y = gbs_stream.get_float() var z = gbs_stream.get_float() model.basepoint[s] = [x, y, z] if model.u1 == 7: model.texpos = gbs_stream.get_32() model.vertexrefs = gbs_stream.get_32() model.vertexref.resize(model.vertexrefs) for s in range(model.vertexrefs): model.vertexref[s] = gbs_stream.get_16() model.points = gbs_stream.get_32() model.point_1.resize(model.points) if model.u1 == 7: model.point_2.resize(model.points) model.point_uv.resize(model.points) # model.point_c.resize(model.points*3) for s in range(model.points): model.point_1[s] = gbs_stream.get_16() if model.u1 == 7: for s in range(model.points): model.point_2[s] = gbs_stream.get_16() for s in range(model.points): model.point_uv[s] = [] model.point_uv[s].resize(2) model.point_uv[s][0] = gbs_stream.get_float() model.point_uv[s][1] = gbs_stream.get_float() for _s in range(model.points): var r = gbs_stream.get_8() var g = gbs_stream.get_8() var b = gbs_stream.get_8() model.point_c.append(r) model.point_c.append(g) model.point_c.append(b) var i = gbs_stream.get_32() model.ref1.resize(i) for s in range(i): model.ref1[s] = [] model.ref1[s].resize(5) model.ref1[s][0] = gbs_stream.get_32() model.ref1[s][1] = gbs_stream.get_32() model.ref1[s][2] = gbs_stream.get_32() model.ref1[s][3] = gbs_stream.get_32() model.ref1[s][4] = gbs_stream.get_32() model.parts = gbs_stream.get_32() model.part.resize(model.parts) for p in range(model.parts): model.part[p] = modelitem_gd.ModelItem.new() model.part[p].objname = gbs_stream.get_string(32) model.part[p].objindex = gbs_stream.get_32() model.part[p].refs = gbs_stream.get_32() model.part[p].wordz = gbs_stream.get_32() model.part[p].refs_ = gbs_stream.get_16() model.part[p].triangle.resize(model.part[p].refs) for s in range(model.part[p].refs): model.part[p].triangle[s] = [] model.part[p].triangle[s].resize(3) model.part[p].triangle[s][0] = gbs_stream.get_16() model.part[p].triangle[s][1] = gbs_stream.get_16() model.part[p].triangle[s][2] = gbs_stream.get_16() model.part[p].refstart = gbs_stream.get_32() model.part[p].refnum = gbs_stream.get_32() model.part[p].texture = gbs_stream.get_string(32).to_lower() model.part[p].bumptexture = gbs_stream.get_string(32).to_lower() model.part[p].falloff = gbs_stream.get_float() model.part[p].blend = gbs_stream.get_float() model.part[p].flags = gbs_stream.get_32() model.part[p].emissive = gbs_stream.get_32() model.part[p].ambiant = gbs_stream.get_32() model.part[p].diffuse = gbs_stream.get_32() model.part[p].specular = gbs_stream.get_32() model.part[p].power = gbs_stream.get_float() model.tex.resize(model.parts) for s in range(model.parts): if model.part[s].texture != "": model.tex[s] = load_texture(model.part[s].texture+".tga") else: model.tex[s] = null model.bounds1 = model.basepoint[0] model.bounds2 = model.basepoint[0] model.maxbound = 0 for s in range(model.basepoints): var r = sqrt(pow(model.basepoint[s][0], 2) + pow(model.basepoint[s][1], 2) + pow(model.basepoint[s][2], 2)) if r > model.maxbound: model.maxbound = r for s in range(model.basepoints): if model.basepoint[s][0] < model.bounds1[0]: model.bounds1[0] = model.basepoint[s][0] if model.basepoint[s][1] < model.bounds1[1]: model.bounds1[1] = model.basepoint[s][1] if model.basepoint[s][2] < model.bounds1[2]: model.bounds1[2] = model.basepoint[s][2] if model.basepoint[s][0] > model.bounds2[0]: model.bounds2[0] = model.basepoint[s][0] if model.basepoint[s][1] > model.bounds2[1]: model.bounds2[1] = model.basepoint[s][1] if model.basepoint[s][2] > model.bounds2[2]: model.bounds2[2] = model.basepoint[s][2] return model func load_texture(texture_file: String) -> ImageTexture: print("Loading texture "+texture_file) var tmpDirectory = Directory.new() if not tmpDirectory.dir_exists("user://tmp"): tmpDirectory.make_dir("user://tmp") var stream = read_file_in_gzp(texture_file) if stream == null: return null var tmpFile = File.new() tmpFile.open("user://tmp/"+texture_file, File.WRITE) tmpFile.store_buffer(stream.data_array) print("Saved to: "+tmpFile.get_path_absolute()) tmpFile.close() var img = Image.new() var tex = ImageTexture.new() img.load("user://tmp/"+texture_file) tex.create_from_image(img) tmpDirectory.remove("user://tmp/"+texture_file) return tex func load_model_mesh(model) -> MeshInstance: var meshinstance = MeshInstance.new() var mesh = Mesh.new() for i in range(model.parts): var st = SurfaceTool.new() st.begin(Mesh.PRIMITIVE_TRIANGLES) var mat = SpatialMaterial.new() mat.params_cull_mode = SpatialMaterial.CULL_DISABLED mat.flags_unshaded = true if model.tex[i]: mat.albedo_texture = model.tex[i] if mat.albedo_texture.has_alpha(): # mat.flags_transparent = true # mat.params_blend_mode = SpatialMaterial.BLEND_MODE_MIX pass else: mat.vertex_color_use_as_albedo = true st.set_material(mat) # assert(len(model.basepoint) % 3 == 0) for j in range(len(model.part[i].triangle)): for k in range(3): var l = model.part[i].triangle[j][k] st.add_uv(Vector2(model.point_uv[l][0], model.point_uv[l][1])) st.add_color(Color( model.point_c[l*3+0] / 255.0 + (model.part[i].diffuse & 255) / 255.0, model.point_c[l*3+1] / 255.0 + ((model.part[i].diffuse >> 8) & 255) / 255.0, model.point_c[l*3+2] / 255.0 + ((model.part[i].diffuse >> 16) & 255) / 255.0)) l = model.point_1[l] st.add_vertex(Vector3( model.basepoint[l][0], model.basepoint[l][2], model.basepoint[l][1])) mesh = st.commit(mesh) meshinstance.mesh = mesh return meshinstance func _decompress(compressed_bytes: PoolByteArray, original_size: int) -> PoolByteArray: var i = 0 var j = 0 var dec_byte = 0 var dec_bits = 8 var buff_start = 0xFEE var res = PoolByteArray() res.resize(original_size) if (original_size == 0): return res while j < original_size: if dec_bits == 8: dec_byte = compressed_bytes[i] i+=1 dec_bits = 0 if (dec_byte >> dec_bits & 1) == 0: var dec_pos = ((compressed_bytes[i] + ((compressed_bytes[i + 1] & 0xF0) << 4) - buff_start - j) & 0xFFF) - 0x1000 + j var dec_len = (compressed_bytes[i + 1] & 0xF) + 3 i+=2 while dec_len > 0: if dec_pos >= 0: res[j] = res[dec_pos] else: res[j] = 32 j+=1 dec_pos += 1 dec_len -= 1 else: res[j] = compressed_bytes[i] i+=1 j+=1 dec_bits += 1 return res