add tim vram layout
This commit is contained in:
parent
c0d2d8a3ca
commit
9ab55e1141
@ -111,6 +111,8 @@ You'll need to have [pngquant](https://pngquant.org/) and [img2tim](https://gith
|
||||
|
||||
Windows executables are provided for convenience.
|
||||
|
||||
For users with Imagemagick installed, there is an option to use that instead of pngquant.
|
||||
|
||||
On Linux, that's :
|
||||
|
||||
`~/.config/blender/2.79/scripts/addons`
|
||||
|
@ -20,7 +20,7 @@ import unicodedata
|
||||
|
||||
import subprocess
|
||||
|
||||
from math import radians, degrees, floor, cos, sin, sqrt
|
||||
from math import radians, degrees, floor, cos, sin, sqrt, ceil
|
||||
|
||||
from mathutils import Vector
|
||||
|
||||
@ -91,7 +91,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
name = "Use ImageMagick",
|
||||
|
||||
description = "Use Image Magick's convert tool to convert PNGs to 8/4bpp",
|
||||
description = "Use installed Image Magick's convert tool to convert PNGs to 8/4bpp",
|
||||
|
||||
default = False
|
||||
)
|
||||
@ -108,6 +108,18 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
### Globals declaration
|
||||
|
||||
global nextTpage, freeTpage
|
||||
|
||||
global nextClutSlot, freeClutSlot
|
||||
|
||||
global tpageY
|
||||
|
||||
global TIMbpp
|
||||
|
||||
### Functions
|
||||
|
||||
def triangulate_object(obj):
|
||||
|
||||
# Triangulate an object's mesh
|
||||
@ -342,7 +354,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
return screenPos
|
||||
|
||||
def convertBGtoTIM( filePathWithExt, colors = 256, bpp = 8):
|
||||
def convertBGtoTIM( filePathWithExt, colors = 256, bpp = 8, timX = 640, timY = 0, clutX = 0, clutY = 480, transparency = 'alpha'):
|
||||
|
||||
# By default, converts a RGB to 8bpp, 256 colors indexed PNG, then to a 8bpp TIM image
|
||||
|
||||
@ -372,6 +384,18 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
colors = min( 16, colors )
|
||||
|
||||
if transparency == "alpha":
|
||||
|
||||
transpMethod = "-usealpha"
|
||||
|
||||
elif transparency == "black":
|
||||
|
||||
transpMethod = "-b"
|
||||
|
||||
elif transparency == "nonblack":
|
||||
|
||||
transpMethod = "-t"
|
||||
|
||||
# Quantization of colors with pngquant ( https://pngquant.org/ )
|
||||
|
||||
subprocess.call( [ "pngquant" + exe, str( colors ), filePathWithExt, "-o", filePathWithExt, "--force" ] )
|
||||
@ -386,14 +410,171 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
# Convert to tim with img2tim ( https://github.com/Lameguy64/img2tim )
|
||||
|
||||
subprocess.call( [ "img2tim" + exe, "-t", "-bpp", str( bpp ), "-org", "320", "0", "-plt" , "0", "484","-o", filePathWithoutExt + ".tim", filePathWithExt ] )
|
||||
subprocess.call( [ "img2tim" + exe, transpMethod, "-bpp", str( bpp ), "-org", str( timX ), str( timY ), "-plt" , str( clutX ), str( clutY ),"-o", filePathWithoutExt + ".tim", filePathWithExt ] )
|
||||
|
||||
def VramIsFull( size ):
|
||||
|
||||
# Returns True if not enough space in Vram for image
|
||||
|
||||
# Transpose bpp to bitshift value
|
||||
|
||||
global nextTpage, freeTpage
|
||||
|
||||
global nextClutSlot, freeClutSlot
|
||||
|
||||
global tpageY
|
||||
|
||||
if TIMbpp == 8:
|
||||
|
||||
shift = 1
|
||||
|
||||
elif TIMbpp == 4:
|
||||
|
||||
shift = 2
|
||||
|
||||
else:
|
||||
|
||||
shift = 0
|
||||
|
||||
# Get image width in vram
|
||||
|
||||
if not size:
|
||||
|
||||
imageWidth = size[0] >> shift
|
||||
|
||||
else:
|
||||
|
||||
imageWidth = size >> shift
|
||||
|
||||
# Divide by cell width ( 64 pixels )
|
||||
|
||||
imageWidthInTPage = ceil( imageWidth / 64 )
|
||||
|
||||
if ( tpageY == 0 and
|
||||
|
||||
nextTpage + ( imageWidthInTPage * 64 ) < 1024 and
|
||||
|
||||
freeTpage - imageWidthInTPage > 0
|
||||
|
||||
) :
|
||||
|
||||
return False
|
||||
|
||||
|
||||
elif ( tpageY == 256 and
|
||||
|
||||
nextTpage + ( imageWidthInTPage * 64 ) < 960 and
|
||||
|
||||
freeTpage - imageWidthInTPage > 1
|
||||
|
||||
) :
|
||||
|
||||
return False
|
||||
|
||||
else:
|
||||
|
||||
return True
|
||||
|
||||
def setNextTimPos( image ):
|
||||
|
||||
# Sets nextTpage, freeTpage, tpageY, nextClutSlot, freeClutSlot to next free space in Vram
|
||||
|
||||
|
||||
# Transpose bpp to bitshift value
|
||||
|
||||
global nextTpage, freeTpage
|
||||
|
||||
global nextClutSlot, freeClutSlot
|
||||
|
||||
global tpageY
|
||||
|
||||
if TIMbpp == 8:
|
||||
|
||||
shift = 1
|
||||
|
||||
elif TIMbpp == 4:
|
||||
|
||||
shift = 2
|
||||
|
||||
else:
|
||||
|
||||
shift = 0
|
||||
|
||||
# Get image width in vram
|
||||
|
||||
imageWidth = image.size[0] >> shift
|
||||
|
||||
# Divide by cell width ( 64 pixels )
|
||||
|
||||
imageWidthInTPage = ceil( imageWidth / 64 )
|
||||
|
||||
if ( tpageY == 0 and
|
||||
|
||||
nextTpage + ( imageWidthInTPage * 64 ) < 1024 and
|
||||
|
||||
freeTpage - imageWidthInTPage > 0
|
||||
|
||||
) :
|
||||
|
||||
nextTpage += imageWidthInTPage * 64
|
||||
|
||||
freeTpage -= imageWidthInTPage
|
||||
|
||||
nextClutSlot += 1
|
||||
|
||||
freeClutSlot -= 1
|
||||
|
||||
|
||||
elif ( tpageY == 256 and
|
||||
|
||||
nextTpage + ( imageWidthInTPage * 64 ) < 960 and
|
||||
|
||||
freeTpage - imageWidthInTPage > 1
|
||||
|
||||
) :
|
||||
|
||||
nextTpage += imageWidthInTPage * 64
|
||||
|
||||
freeTpage -= imageWidthInTPage
|
||||
|
||||
nextClutSlot += 1
|
||||
|
||||
freeClutSlot -= 1
|
||||
|
||||
else:
|
||||
|
||||
tpageY = 256
|
||||
|
||||
nextTpage = 320
|
||||
|
||||
nextClutSlot += 1
|
||||
|
||||
freeClutSlot -= 1
|
||||
|
||||
### VRam Layout
|
||||
|
||||
nextTpage = 320
|
||||
|
||||
nextClutSlot = 480
|
||||
|
||||
freeTpage = 21
|
||||
|
||||
freeClutSlot = 32
|
||||
|
||||
tpageY = 0
|
||||
|
||||
# Set TIMs default bpp value
|
||||
|
||||
TIMbpp = 8
|
||||
|
||||
TIMshift = 1
|
||||
|
||||
if self.exp_TIMbpp:
|
||||
|
||||
TIMbpp = 4
|
||||
|
||||
TIMshift = 2
|
||||
|
||||
# Leave edit mode to avoid errors
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
@ -434,6 +615,18 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
if self.exp_Precalc:
|
||||
|
||||
# Set rendering resolution
|
||||
|
||||
bpy.context.scene.render.resolution_x = 320
|
||||
|
||||
bpy.context.scene.render.resolution_y = 240
|
||||
|
||||
# Get BGs TIM size depending on mode
|
||||
|
||||
timSize = bpy.context.scene.render.resolution_x >> TIMshift
|
||||
|
||||
timSizeInCell = ceil( timSize / 64 )
|
||||
|
||||
# Create folder if it doesn't exist
|
||||
|
||||
os.makedirs(dirpath, exist_ok = 1)
|
||||
@ -448,6 +641,8 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
bpy.context.scene.render.image_settings.color_depth = '8'
|
||||
|
||||
bpy.context.scene.render.image_settings.color_mode = 'RGB'
|
||||
|
||||
# Get active cam
|
||||
|
||||
scene = bpy.context.scene
|
||||
@ -482,12 +677,35 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
# Convert PNG to TIM
|
||||
|
||||
convertBGtoTIM( filepath + filename + fileext , bpp = TIMbpp )
|
||||
if not VramIsFull( bpy.context.scene.render.resolution_x ):
|
||||
|
||||
convertBGtoTIM( filepath + filename + fileext , bpp = TIMbpp, timX = nextTpage, timY = tpageY, clutY = nextClutSlot )
|
||||
|
||||
else:
|
||||
|
||||
tpageY = 256
|
||||
|
||||
nextTpage = 320
|
||||
|
||||
if not VramIsFull( bpy.context.scene.render.resolution_x ):
|
||||
|
||||
convertBGtoTIM( filepath + filename + fileext , bpp = TIMbpp, timX = nextTpage, timY = tpageY, clutY = nextClutSlot )
|
||||
|
||||
# Add camera object to camAngles
|
||||
|
||||
camAngles.append(o)
|
||||
|
||||
# Notify layout change to vars
|
||||
|
||||
nextTpage += timSizeInCell * 64
|
||||
|
||||
freeTpage -= timSizeInCell
|
||||
|
||||
nextClutSlot += 1
|
||||
|
||||
freeClutSlot -= 1
|
||||
|
||||
print( str(freeTpage) + " : " + str(nextTpage) + " : " + str(nextClutSlot) + " : " + str(freeClutSlot) )
|
||||
|
||||
### Start writing output file
|
||||
|
||||
@ -674,9 +892,19 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
f.write("CAMPOS camPos_" + CleanName( bpy.data.objects[ o ].name ) + " = {\n" +
|
||||
|
||||
"\t{" + str(round(-bpy.data.objects[o].location.x * scale)) + "," + str(round(bpy.data.objects[o].location.z * scale)) + "," +str(round(-bpy.data.objects[o].location.y * scale)) + "},\n" +
|
||||
"\t{ " + str( round( -bpy.data.objects[o].location.x * scale ) ) +
|
||||
|
||||
"\t{" + str(round(-(degrees(bpy.data.objects[o].rotation_euler.x)-90)/360 * 4096)) + "," + str(round(degrees(bpy.data.objects[o].rotation_euler.z)/360 * 4096)) + "," + str(round(-(degrees(bpy.data.objects[o].rotation_euler.y))/360 * 4096)) + "}\n" +
|
||||
"," + str( round( bpy.data.objects[o].location.z * scale ) ) +
|
||||
|
||||
"," + str( round( -bpy.data.objects[o].location.y * scale ) ) + " },\n" +
|
||||
|
||||
"\t{ " + str( round( -( degrees( bpy.data.objects[ o ].rotation_euler.x ) -90 ) / 360 * 4096 ) ) +
|
||||
|
||||
"," + str( round( degrees( bpy.data.objects[ o ].rotation_euler.z ) / 360 * 4096 ) ) +
|
||||
|
||||
"," + str( round( -( degrees( bpy.data.objects[ o ].rotation_euler.y ) ) / 360 * 4096 ) ) +
|
||||
|
||||
" }\n" +
|
||||
|
||||
"};\n\n")
|
||||
|
||||
@ -684,7 +912,11 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
if bpy.data.objects[o].type == 'CAMERA' :
|
||||
|
||||
if bpy.data.objects[o].name.startswith("camPath") and not bpy.data.objects[o].data.get('isDefault'):
|
||||
if ( bpy.data.objects[ o ].name.startswith( "camPath" ) and not
|
||||
|
||||
bpy.data.objects[ o ].data.get( 'isDefault' )
|
||||
|
||||
) :
|
||||
|
||||
camPathPoints.append(bpy.data.objects[o].name)
|
||||
|
||||
@ -696,9 +928,9 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
# ~ camPathPoints = list(reversed(camPathPoints))
|
||||
|
||||
for p in range(len(camPathPoints)):
|
||||
for point in range(len(camPathPoints)):
|
||||
|
||||
if p == 0:
|
||||
if point == 0:
|
||||
|
||||
f.write("CAMPATH camPath = {\n" +
|
||||
|
||||
@ -710,9 +942,15 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
"\t{\n")
|
||||
|
||||
f.write("\t\t{" + str(round(-bpy.data.objects[camPathPoints[p]].location.x * scale)) + "," + str(round(bpy.data.objects[camPathPoints[p]].location.z * scale)) + "," +str(round(-bpy.data.objects[camPathPoints[p]].location.y * scale)) + "}")
|
||||
f.write( "\t\t{ " + str( round( -bpy.data.objects[ camPathPoints[ point ] ].location.x * scale ) ) +
|
||||
|
||||
if p != len(camPathPoints) - 1:
|
||||
"," + str( round( bpy.data.objects[ camPathPoints[ point ] ].location.z * scale ) ) +
|
||||
|
||||
"," + str( round( -bpy.data.objects[ camPathPoints[ point ] ].location.y * scale ) ) +
|
||||
|
||||
" }" )
|
||||
|
||||
if point != len( camPathPoints ) - 1:
|
||||
|
||||
f.write(",\n")
|
||||
|
||||
@ -869,7 +1107,11 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
Zvals.append( -v.z )
|
||||
|
||||
f.write("\t{"+str(round(v.x*scale))+","+str(round(-v.z*scale)) + "," + str(round(v.y*scale)) +"}")
|
||||
f.write("\t{ " + str( round( v.x * scale ) ) +
|
||||
|
||||
"," + str( round( -v.z * scale ) ) +
|
||||
|
||||
"," + str( round( v.y * scale ) ) + " }" )
|
||||
|
||||
if i != len(m.vertices) - 1:
|
||||
|
||||
@ -887,7 +1129,11 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
poly = m.vertices[i]
|
||||
|
||||
f.write("\t"+str(round(-poly.normal.x * 4096))+","+str(round(poly.normal.z * 4096))+","+str(round(-poly.normal.y * 4096))+",0")
|
||||
f.write( "\t"+ str( round( -poly.normal.x * 4096 ) ) +
|
||||
|
||||
"," + str( round( poly.normal.z * 4096 ) ) +
|
||||
|
||||
"," + str( round( -poly.normal.y * 4096 ) ) + ", 0" )
|
||||
|
||||
if i != len(m.vertices) - 1:
|
||||
|
||||
@ -923,7 +1169,13 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
uy = u.y * tex_height
|
||||
|
||||
f.write("\t"+str(max(0, min( round(ux) , 255 )))+","+str(max(0, min(round(tex_height - uy) , 255 )))+", 0, 0") # Clamp values to 0-255 to avoid tpage overflow
|
||||
# Clamp values to 0-255 to avoid tpage overflow
|
||||
|
||||
f.write("\t" + str( max( 0, min( round( ux ) , 255 ) ) ) +
|
||||
|
||||
"," + str( max( 0, min( round( tex_height - uy ) , 255 ) ) ) +
|
||||
|
||||
", 0, 0" )
|
||||
|
||||
if i != len(uv_layer) - 1:
|
||||
|
||||
@ -945,6 +1197,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
texture_image.save()
|
||||
|
||||
|
||||
# Write vertex colors vectors
|
||||
|
||||
f.write("CVECTOR "+"model"+cleanName+"_color[] = {\n")
|
||||
@ -957,7 +1210,11 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
for i in range(len(colors)):
|
||||
|
||||
f.write("\t"+str(int(colors[i].color.r*255))+","+str(int(colors[i].color.g*255))+","+str(int(colors[i].color.b*255))+", 0")
|
||||
f.write("\t" + str( int( colors[ i ].color.r * 255 ) ) + "," +
|
||||
|
||||
str( int( colors[ i ].color.g * 255 ) ) + "," +
|
||||
|
||||
str( int( colors[ i ].color.b * 255 ) ) + ", 0" )
|
||||
|
||||
if i != len(colors) - 1:
|
||||
|
||||
@ -1274,7 +1531,35 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
# TODO : Add a way to arrange TIM's VM layout to avoid overlapping
|
||||
|
||||
# ~ convertPNGtoTIM( folder + os.sep + "TIM" + os.sep + CleanName( tex_name ) + "." + texture_image.file_format.lower() , bpp = TIMbpp )
|
||||
filePathWithExt = folder + os.sep + "TIM" + os.sep + CleanName( tex_name ) + "." + texture_image.file_format.lower()
|
||||
|
||||
if not VramIsFull( bpy.context.scene.render.resolution_x ):
|
||||
|
||||
convertBGtoTIM( filePathWithExt, bpp = TIMbpp, timX = nextTpage, timY = tpageY, clutY = nextClutSlot )
|
||||
|
||||
setNextTimPos( texture_image )
|
||||
|
||||
elif VramIsFull( bpy.context.scene.render.resolution_x ) and tpageY == 0:
|
||||
|
||||
tpageY = 256
|
||||
|
||||
nextTpage = 320
|
||||
|
||||
if not VramIsFull( bpy.context.scene.render.resolution_x ):
|
||||
|
||||
convertBGtoTIM( filePathWithExt, bpp = TIMbpp, timX = nextTpage, timY = tpageY, clutY = nextClutSlot )
|
||||
|
||||
setNextTimPos( texture_image )
|
||||
|
||||
else:
|
||||
|
||||
self.report({'ERROR'}, "Not enough space in VRam !")
|
||||
|
||||
else:
|
||||
|
||||
self.report({'ERROR'}, "Not enough space in VRam !")
|
||||
|
||||
print( str(freeTpage) + " : " + str(nextTpage) + " : " + str(nextClutSlot) + " : " + str(freeClutSlot) )
|
||||
|
||||
# Write corresponding TIM declaration
|
||||
|
||||
@ -1894,13 +2179,19 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
if checkLine(
|
||||
|
||||
getSepLine(p, s[0])[0],
|
||||
|
||||
getSepLine(p, s[0])[1],
|
||||
|
||||
getSepLine(p, s[0])[2],
|
||||
|
||||
getSepLine(p, s[0])[3],
|
||||
|
||||
getSepLine(op, s[1])[0],
|
||||
|
||||
getSepLine(op, s[1])[1],
|
||||
|
||||
getSepLine(op, s[1])[2],
|
||||
|
||||
getSepLine(op, s[1])[3]
|
||||
|
||||
) == 'connected' and (
|
||||
|
Loading…
x
Reference in New Issue
Block a user