init
This commit is contained in:
commit
41cfa7e22d
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
venv/
|
||||
.idea
|
||||
__pycache__
|
90
gbs_plugin/__init__.py
Normal file
90
gbs_plugin/__init__.py
Normal file
@ -0,0 +1,90 @@
|
||||
# addon information
|
||||
import bpy
|
||||
from bpy.types import Operator, AddonPreferences
|
||||
from bpy_extras.io_utils import ImportHelper
|
||||
from bpy.props import StringProperty
|
||||
from .importer import imp_gbs
|
||||
import time
|
||||
|
||||
|
||||
|
||||
bl_info = {
|
||||
"name": "Import Giants GBS format",
|
||||
"author": "Amazed#0001",
|
||||
"version": (1, 0),
|
||||
"blender": (2, 80, 0),
|
||||
"location": "File > Import > Giants GBS (.gbs)",
|
||||
"description": "Import static objects from Giants GBS files.",
|
||||
"category": "Import-Export",
|
||||
}
|
||||
|
||||
class GBSPreferences(AddonPreferences):
|
||||
# this must match the addon name, use '__package__'
|
||||
# when defining this in a submodule of a python package.
|
||||
bl_idname = __name__
|
||||
|
||||
game_path = StringProperty(
|
||||
name="Your Giants game folder",
|
||||
description="This is needed to extract textures",
|
||||
subtype='DIR_PATH'
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.label(text="GBS plugin preferences")
|
||||
layout.prop(self, "game_path")
|
||||
|
||||
|
||||
# main code
|
||||
class GBSImporter(bpy.types.Operator, ImportHelper):
|
||||
bl_idname = "gbs_importer.gbs"
|
||||
bl_description = "Import Giants model files (.gbs)"
|
||||
bl_label = "Giants GBS Importer"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
filename_ext = ".gbs"
|
||||
filter_glob: StringProperty(
|
||||
default="*.gbs",
|
||||
options={'HIDDEN'},
|
||||
)
|
||||
|
||||
filter_glob: StringProperty(
|
||||
default="*.gbs",
|
||||
options={'HIDDEN'},
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
user_preferences = context.preferences
|
||||
addon_prefs = user_preferences.addons[__name__].preferences
|
||||
|
||||
time_start = time.time()
|
||||
|
||||
game_path = addon_prefs.game_path
|
||||
|
||||
if not game_path:
|
||||
raise Exception("Please set your Giants folder in the add-on preferences")
|
||||
imp_gbs(self.filepath, game_path)
|
||||
print("Elapsed time: %.2fs" % (time.time() - time_start))
|
||||
return {'FINISHED'}
|
||||
|
||||
classes = (
|
||||
GBSPreferences,
|
||||
GBSImporter
|
||||
)
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(GBSImporter.bl_idname, text="Giants GBS (.gbs)")
|
||||
|
||||
|
||||
def register():
|
||||
for c in classes:
|
||||
bpy.utils.register_class(c)
|
||||
|
||||
bpy.types.TOPBAR_MT_file_import.append(menu_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.TOPBAR_MT_file_import.remove(menu_func)
|
||||
|
||||
for c in classes:
|
||||
bpy.utils.unregister_class(c)
|
63
gbs_plugin/importer.py
Normal file
63
gbs_plugin/importer.py
Normal file
@ -0,0 +1,63 @@
|
||||
from .shared import *
|
||||
|
||||
|
||||
def imp_gbs(gbspath, giantspath):
|
||||
path = gbspath
|
||||
game_folder = giantspath
|
||||
gbs = GbsData()
|
||||
gbs.read(path)
|
||||
name = os.path.splitext(os.path.basename(path))[0]
|
||||
|
||||
map_collection = bpy.data.collections.new(name)
|
||||
bpy.context.scene.collection.children.link(map_collection)
|
||||
|
||||
verts = []
|
||||
for index in gbs.indexed_vertices:
|
||||
v = gbs.vertices[index]
|
||||
vert = (v.x, v.y, v.z)
|
||||
verts.append(vert)
|
||||
|
||||
for subobj in gbs.SubObjs:
|
||||
fool = 0
|
||||
uvs = []
|
||||
|
||||
mesh = bpy.data.meshes.new(subobj.objname)
|
||||
obj = bpy.data.objects.new(mesh.name, mesh)
|
||||
faces = []
|
||||
|
||||
curr_index = 0
|
||||
print(subobj.tridata)
|
||||
while curr_index < len(subobj.tridata) - 1:
|
||||
num_tris = subobj.tridata[curr_index]
|
||||
for tri_num in range(num_tris):
|
||||
curr_face = []
|
||||
for k in range(3):
|
||||
vert_index = subobj.tridata[curr_index + 1 + tri_num * 3 + k]
|
||||
curr_face.append(vert_index)
|
||||
|
||||
u = gbs.vertuv[vert_index].u
|
||||
v = gbs.vertuv[vert_index].v
|
||||
uv = (u, v)
|
||||
uvs.append(uv)
|
||||
|
||||
faces.append(curr_face)
|
||||
curr_index = num_tris * 3 + 1
|
||||
|
||||
mesh.from_pydata(verts, [], faces)
|
||||
map_collection.objects.link(obj)
|
||||
|
||||
# Uvs
|
||||
uv_layer = mesh.uv_layers.new(name="UV")
|
||||
mesh.uv_layers.active = uv_layer
|
||||
|
||||
for i in range(len(uvs)):
|
||||
uv_layer.data[i].uv = uvs[i]
|
||||
|
||||
tmpfilename = find_and_extract_texture(subobj.texname, name, game_folder)
|
||||
mat = material_from_file(tmpfilename, subobj.texname)
|
||||
if obj.data.materials:
|
||||
# assign to 1st material slot
|
||||
obj.data.materials[0] = mat
|
||||
else:
|
||||
# no slots
|
||||
obj.data.materials.append(mat)
|
474
gbs_plugin/shared.py
Normal file
474
gbs_plugin/shared.py
Normal file
@ -0,0 +1,474 @@
|
||||
import struct
|
||||
from typing import List
|
||||
import math
|
||||
import os
|
||||
import tempfile
|
||||
import bpy
|
||||
|
||||
GBS_VERSION = 0xaa0100be
|
||||
GBSFlagNormals = 0x0001
|
||||
GBSFlagUVs = 0x0002
|
||||
GBSFlagRGBs = 0x0004
|
||||
GBSFlagCalcNormals = 0x0008
|
||||
GBSFlagMaxLit = (1 << 31)
|
||||
|
||||
|
||||
def read_int(fp):
|
||||
return struct.unpack("<L", fp.read(4))[0]
|
||||
|
||||
|
||||
def read_byte(fp):
|
||||
return struct.unpack("<B", fp.read(1))[0]
|
||||
|
||||
|
||||
def read_float(fp):
|
||||
return struct.unpack("<f", fp.read(4))[0]
|
||||
|
||||
|
||||
def read_short(fp):
|
||||
return struct.unpack("<H", fp.read(2))[0]
|
||||
|
||||
|
||||
def read_string(fp, size):
|
||||
return read_bytes(fp, size).decode("utf8").replace("\x00", "")
|
||||
|
||||
|
||||
def read_bytes(fp, size):
|
||||
return bytes(struct.unpack('<' + str(size) + 'B', fp.read(size)))
|
||||
|
||||
|
||||
def read_string_until_none(fp) -> str:
|
||||
s = ""
|
||||
c = read_byte(fp)
|
||||
while c != 0x00:
|
||||
s += chr(c)
|
||||
c = read_byte(fp)
|
||||
return s
|
||||
|
||||
|
||||
def decompress(compressed_bytes, original_size: int):
|
||||
i = 0
|
||||
j = 0
|
||||
dec_byte = 0
|
||||
dec_bits = 8
|
||||
buff_start = 0xFEE
|
||||
|
||||
res = bytearray(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:
|
||||
dec_pos = ((compressed_bytes[i] + (
|
||||
(compressed_bytes[i + 1] & 0xF0) << 4) - buff_start - j) & 0xFFF) - 0x1000 + j
|
||||
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
|
||||
|
||||
|
||||
class Vec2:
|
||||
def __init__(self, x=0.0, y=0.0):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def __str__(self):
|
||||
return "[%s,%s]" % (self.x, self.y)
|
||||
|
||||
|
||||
class Vec3:
|
||||
def __init__(self, x=0.0, y=0.0, z=0.0):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.z = z
|
||||
|
||||
def __add__(self, other):
|
||||
return Vec3(self.x + other.x, self.y + other.y, self.z + other.z)
|
||||
|
||||
def __sub__(self, other):
|
||||
return self + -other
|
||||
|
||||
def __radd__(self, other):
|
||||
return Vec3(self.x + other.x, self.y + other.y, self.z + other.z)
|
||||
|
||||
def __mul__(self, scalar):
|
||||
return Vec3(self.x * scalar, self.y * scalar, self.z * scalar)
|
||||
|
||||
def __rmul__(self, scalar):
|
||||
return Vec3(self.x * scalar, self.y * scalar, self.z * scalar)
|
||||
|
||||
def __neg__(self):
|
||||
return Vec3(-self.x, -self.y, -self.z)
|
||||
|
||||
def __pos__(self):
|
||||
return Vec3(self.x, self.y, self.z)
|
||||
|
||||
def __xor__(self, other):
|
||||
cx = self.y * other.z - self.z * other.y
|
||||
cy = self.z * other.x - self.x * other.z
|
||||
cz = self.x * other.y - self.y * other.x
|
||||
return Vec3(cx, cy, cz)
|
||||
|
||||
def cross(self, other):
|
||||
return self ^ other
|
||||
|
||||
def normalize(self):
|
||||
w = math.sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2)
|
||||
if w == 0:
|
||||
return Vec3()
|
||||
else:
|
||||
return Vec3(self.x / w, self.y / w, self.z / w)
|
||||
|
||||
def __str__(self):
|
||||
return "[%s,%s,%s]" % (self.x, self.y, self.z)
|
||||
|
||||
|
||||
class VecRGB:
|
||||
def __init__(self, r=0, g=0, b=0):
|
||||
self.r = r
|
||||
self.g = g
|
||||
self.b = b
|
||||
|
||||
def __str__(self):
|
||||
return "[%s,%s,%s]" % (self.r, self.g, self.b)
|
||||
|
||||
|
||||
def cross(v1: Vec3, v2: Vec3):
|
||||
return v1.cross(v2)
|
||||
|
||||
|
||||
def resize(li: List, t, num):
|
||||
li.clear()
|
||||
for i in range(num):
|
||||
li.append(t())
|
||||
|
||||
|
||||
class FileMaxObj:
|
||||
def __init__(self):
|
||||
self.vstart: int = 0
|
||||
self.vcount: int = 0
|
||||
self.nstart: int = 0
|
||||
self.ncount: int = 0
|
||||
self.noffset: int = 0
|
||||
|
||||
|
||||
class MaxObj(FileMaxObj):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.fstart: int = 0
|
||||
self.fcount: int = 0
|
||||
self.sostart: int = 0
|
||||
self.socount: int = 0
|
||||
|
||||
|
||||
class SubObject:
|
||||
def __init__(self):
|
||||
self.objname: str = ""
|
||||
self.maxobjindex: int = 0
|
||||
self.ntris: int = 0 # count of tridata (including preceding 'count' short)
|
||||
self.totaltris: int = 0
|
||||
self.tridata: List[int] = [] # unsigned short
|
||||
self.verticeref_start: int = 0
|
||||
self.verticeref_count: int = 0
|
||||
self.texname: str = ""
|
||||
self.bumptexture: str = ""
|
||||
self.falloff: float = 0
|
||||
self.blend: float = 0
|
||||
self.flags: int = 0
|
||||
self.emissive: int = 0
|
||||
self.ambient: int = 0
|
||||
self.diffuse: int = 0
|
||||
self.specular: int = 0
|
||||
self.power: int = 0
|
||||
|
||||
|
||||
class UV:
|
||||
def __init__(self, u: float = 0, v: float = 0):
|
||||
self.u: float = u
|
||||
self.v: float = v
|
||||
|
||||
|
||||
class GbsData:
|
||||
def __init__(self):
|
||||
self.name = ""
|
||||
self.optionsflags: int = 0
|
||||
self.nndefs: int = 0
|
||||
self.num_normals: int = 0
|
||||
self.normals: List[int] = [] # word
|
||||
self.indexed_normals: List[int] = [] # unsigned short
|
||||
self.num_vertices: int = 0
|
||||
self.vertices: List[Vec3] = []
|
||||
self.nsobjs: int = 0
|
||||
self.nmobjs: int = 0
|
||||
self.indexed_vertices: List[int] = [] # unsigned short
|
||||
self.vertrgb: List[VecRGB] = []
|
||||
self.nverts: int = 0
|
||||
self.vertuv: List[UV] = []
|
||||
self.MaxObjs: List[MaxObj] = []
|
||||
self.SubObjs: List[SubObject] = []
|
||||
|
||||
def read(self, file):
|
||||
debug = True
|
||||
self.name = os.path.basename(file)
|
||||
with open(file, "rb") as fp:
|
||||
version_header = read_int(fp)
|
||||
if version_header != GBS_VERSION:
|
||||
raise Exception("File does not appear to be a GBS file.")
|
||||
|
||||
self.optionsflags = read_int(fp)
|
||||
self.num_vertices = read_int(fp)
|
||||
resize(self.vertices, Vec3, self.num_vertices)
|
||||
for i in range(self.num_vertices):
|
||||
self.vertices[i].x = read_float(fp)
|
||||
self.vertices[i].y = read_float(fp)
|
||||
self.vertices[i].z = read_float(fp)
|
||||
|
||||
if self.optionsflags & GBSFlagNormals:
|
||||
self.nndefs = read_int(fp)
|
||||
self.num_normals = read_int(fp)
|
||||
resize(self.normals, int, self.num_normals)
|
||||
for i in range(self.num_normals):
|
||||
self.normals[i] = read_short(fp)
|
||||
|
||||
self.nverts = read_int(fp)
|
||||
if debug: print(
|
||||
"NVERTS=%s, NUMVERTICES=%s, options=%s" % (self.nverts, self.num_vertices, self.optionsflags))
|
||||
resize(self.indexed_vertices, int, self.nverts)
|
||||
for i in range(self.nverts):
|
||||
self.indexed_vertices[i] = read_short(fp)
|
||||
if debug: print(self.indexed_vertices)
|
||||
|
||||
if self.optionsflags & GBSFlagNormals:
|
||||
resize(self.indexed_normals, int, self.nverts)
|
||||
for i in range(self.nverts):
|
||||
self.indexed_normals[i] = read_short(fp)
|
||||
|
||||
if self.optionsflags & GBSFlagUVs:
|
||||
resize(self.vertuv, UV, self.nverts)
|
||||
if debug: print("Read %s UV" % self.nverts)
|
||||
for i in range(self.nverts):
|
||||
self.vertuv[i].u = read_float(fp)
|
||||
self.vertuv[i].v = read_float(fp) * -1
|
||||
|
||||
if self.optionsflags & GBSFlagRGBs:
|
||||
resize(self.vertrgb, VecRGB, self.nverts)
|
||||
if debug: print("Read %s RGB" % self.nverts)
|
||||
for i in range(self.nverts):
|
||||
self.vertrgb[i].r = read_byte(fp)
|
||||
self.vertrgb[i].g = read_byte(fp)
|
||||
self.vertrgb[i].b = read_byte(fp)
|
||||
|
||||
# Get number of objects
|
||||
self.nmobjs = read_int(fp)
|
||||
if debug: print("NMOBJS = %s" % self.nmobjs)
|
||||
resize(self.MaxObjs, MaxObj, self.nmobjs)
|
||||
for maxobj in self.MaxObjs:
|
||||
print("Processing new maxobj")
|
||||
fileMaxObj = FileMaxObj()
|
||||
fileMaxObj.vstart = read_int(fp)
|
||||
fileMaxObj.vcount = read_int(fp)
|
||||
fileMaxObj.nstart = read_int(fp)
|
||||
fileMaxObj.ncount = read_int(fp)
|
||||
fileMaxObj.noffset = read_int(fp)
|
||||
print("vstart=%s vcount=%s nstart=%s ncount=%s noffset=%s" % (
|
||||
fileMaxObj.vstart, fileMaxObj.vcount, fileMaxObj.nstart, fileMaxObj.ncount, fileMaxObj.noffset))
|
||||
maxobj.vstart = fileMaxObj.vstart
|
||||
maxobj.vcount = fileMaxObj.vcount
|
||||
maxobj.nstart = fileMaxObj.nstart
|
||||
maxobj.ncount = fileMaxObj.ncount
|
||||
maxobj.noffset = fileMaxObj.noffset
|
||||
maxobj.fstart = 0
|
||||
maxobj.fcount = 0
|
||||
maxobj.sostart = 0
|
||||
maxobj.socount = 0
|
||||
|
||||
# verify max obj
|
||||
nmcount = 0
|
||||
for maxobj in self.MaxObjs:
|
||||
nmcount += maxobj.vcount
|
||||
assert nmcount == self.num_vertices
|
||||
|
||||
self.nsobjs = read_int(fp)
|
||||
print("Subobject count: %s" % self.nsobjs)
|
||||
resize(self.SubObjs, SubObject, self.nsobjs)
|
||||
num_faces = 0
|
||||
len_tridata = 0
|
||||
for ns in range(self.nsobjs):
|
||||
if debug: print("Processing subobj %s" % ns)
|
||||
object = self.SubObjs[ns]
|
||||
object.objname = read_string(fp, 32)
|
||||
object.maxobjindex = read_int(fp)
|
||||
object.totaltris = read_int(fp)
|
||||
if debug: print("read %s totaltris" % object.totaltris)
|
||||
num_faces += object.totaltris
|
||||
object.ntris = read_int(fp)
|
||||
|
||||
assert ((object.ntris - 1) / 3 == object.totaltris)
|
||||
|
||||
resize(object.tridata, int, object.ntris + 1)
|
||||
if debug: print("read gbs: totaltris: %s, tridata is %s long, ntris: %s" % (
|
||||
object.totaltris, len(object.tridata), object.ntris))
|
||||
len_tridata += object.ntris + 1
|
||||
for i in range(object.ntris):
|
||||
object.tridata[i] = read_short(fp)
|
||||
|
||||
# if debug: print("tridata: %s" % object.tridata)
|
||||
|
||||
object.verticeref_start = read_int(fp)
|
||||
object.verticeref_count = read_int(fp)
|
||||
if self.optionsflags & GBSFlagUVs:
|
||||
object.texname = read_string(fp, 32)
|
||||
object.bumptexture = read_string(fp, 32)
|
||||
|
||||
object.falloff = read_float(fp)
|
||||
if self.optionsflags & GBSFlagRGBs:
|
||||
object.blend = read_float(fp)
|
||||
|
||||
object.flags = read_int(fp)
|
||||
object.emissive = read_int(fp)
|
||||
object.ambient = read_int(fp)
|
||||
object.diffuse = read_int(fp)
|
||||
object.specular = read_int(fp)
|
||||
object.power = read_float(fp)
|
||||
if debug: print(
|
||||
"%s (%s) falloff: %s, blend: %s, flags:%s, emissive: %s, ambiant: %s, diffuse: %s, specular: %s, power: %s" % (
|
||||
object.objname, object.texname, object.falloff, object.blend, object.flags, object.emissive,
|
||||
object.ambient, object.diffuse, object.specular, object.power))
|
||||
|
||||
maxobj = self.MaxObjs[object.maxobjindex]
|
||||
maxobj.fcount += object.totaltris
|
||||
if not maxobj.socount:
|
||||
maxobj.socount = ns
|
||||
|
||||
maxobj.socount += 1
|
||||
if debug: print("read num_faces: %s, len_tridata: %s" % (num_faces, len_tridata))
|
||||
|
||||
@staticmethod
|
||||
def evaluate_tridata(tridata, tri_idx, count):
|
||||
if count == 0:
|
||||
count = tridata[0]
|
||||
if count == 0:
|
||||
return False
|
||||
tri_idx = 0
|
||||
v1 = tridata[tri_idx + 1]
|
||||
v2 = tridata[tri_idx + 2]
|
||||
v3 = tridata[tri_idx + 3]
|
||||
tri_idx += 3
|
||||
|
||||
count -= 1
|
||||
if count < 0:
|
||||
count = 0xffff # max unsigned short
|
||||
if count == 0:
|
||||
tridata = tridata[tridata[0] * 3 + 1:]
|
||||
return tridata, tri_idx, count, v1, v2, v3
|
||||
|
||||
def generate_normals(self):
|
||||
normals: List[Vec3] = []
|
||||
resize(normals, Vec3, self.num_vertices)
|
||||
for subobj_i in range(len(self.SubObjs)):
|
||||
subobj = self.SubObjs[subobj_i]
|
||||
tridata = subobj.tridata
|
||||
values = self.evaluate_tridata(tridata, -1, 0)
|
||||
while values:
|
||||
tridata, tri_idx, count, v1, v2, v3 = values
|
||||
try:
|
||||
p = cross(self.vertices[self.indexed_vertices[v2]] - self.vertices[self.indexed_vertices[v1]],
|
||||
self.vertices[self.indexed_vertices[v3]] - self.vertices[self.indexed_vertices[v1]])
|
||||
except Exception as e:
|
||||
raise e
|
||||
normals[self.indexed_vertices[v1]] += p
|
||||
normals[self.indexed_vertices[v2]] += p
|
||||
normals[self.indexed_vertices[v3]] += p
|
||||
values = self.evaluate_tridata(tridata, tri_idx, count)
|
||||
|
||||
for i in range(len(normals)):
|
||||
normals[i] = normals[i].normalize()
|
||||
return normals
|
||||
|
||||
|
||||
def find_and_extract_texture(texture_filename, objname, giantspath):
|
||||
game_folder = giantspath
|
||||
game_folder = game_folder + "/Bin"
|
||||
|
||||
for gzp_filename in os.listdir(game_folder):
|
||||
if not gzp_filename.endswith(".gzp"):
|
||||
continue
|
||||
|
||||
gzp_fp = open(game_folder + "/" + gzp_filename, "rb")
|
||||
|
||||
checksum = read_int(gzp_fp)
|
||||
if checksum != 0x6608F101:
|
||||
raise Exception("Invalid GZP checksum")
|
||||
|
||||
meta_info_offset = read_int(gzp_fp)
|
||||
|
||||
gzp_fp.seek(meta_info_offset)
|
||||
unk = read_int(gzp_fp)
|
||||
entries_count = read_int(gzp_fp)
|
||||
|
||||
if entries_count == 0:
|
||||
continue
|
||||
|
||||
for index in range(entries_count):
|
||||
compressed_size = read_int(gzp_fp)
|
||||
original_size = read_int(gzp_fp)
|
||||
file_time = read_int(gzp_fp)
|
||||
content_offset = read_int(gzp_fp) + 16
|
||||
compression = read_byte(gzp_fp) # compression: 1 if compressed else 0
|
||||
name_length = read_byte(gzp_fp)
|
||||
name = read_bytes(gzp_fp, name_length).decode("utf8").strip('\x00')
|
||||
|
||||
texture_name = name.lower()
|
||||
if not texture_name.endswith(".tga"):
|
||||
continue
|
||||
|
||||
texture_name = texture_name[0:-4]
|
||||
if texture_name != texture_filename.lower():
|
||||
continue
|
||||
|
||||
curr_pos = gzp_fp.tell()
|
||||
gzp_fp.seek(content_offset)
|
||||
buffer = gzp_fp.read(compressed_size)
|
||||
gzp_fp.seek(curr_pos)
|
||||
|
||||
if compression == 1:
|
||||
buffer = decompress(buffer, original_size)
|
||||
|
||||
fd, filename = tempfile.mkstemp(suffix=".tga", prefix=objname, dir=None, text=False)
|
||||
with open(filename, "wb") as entry_fp:
|
||||
entry_fp.write(buffer)
|
||||
|
||||
return filename
|
||||
return None
|
||||
|
||||
|
||||
def material_from_file(filename, matname):
|
||||
image = bpy.data.images.load(filename, check_existing=True)
|
||||
texture = bpy.data.textures.new(matname, type='IMAGE')
|
||||
texture.image = image
|
||||
|
||||
mat = bpy.data.materials.new(matname)
|
||||
mat.preview_render_type = 'FLAT'
|
||||
mat.use_nodes = True
|
||||
bsdf = mat.node_tree.nodes["Principled BSDF"]
|
||||
texImage = mat.node_tree.nodes.new('ShaderNodeTexImage')
|
||||
texImage.image = image
|
||||
mat.node_tree.links.new(bsdf.inputs['Base Color'], texImage.outputs['Color'])
|
||||
return mat
|
Loading…
Reference in New Issue
Block a user