Skip to content
View in the app

A better way to browse. Learn more.

ResHax

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
Help us keep the site running.

[PC] Richard Burns Rally .SGS/.SGC models

Featured Replies

  • Localization

I know the guys over at the RBR community are at least planning to work on the game's model formats so they can be edited in Blender, but I'd like to know if it's possible to rip them for the time being as I've tried ripping the character models from it using Ninja Ripper but ended up not getting a T-pose.

SGS.7z Cars.7z

Solved by shak-otay

  • Supporter

Low poly models usually don't raise that big interest but the mesh format shouldn't be a big obstacle, or should it?

corolla-sgc.png

edit: didn't know whether triangle strips is the best choice here. Saved with normal triangles, drag&dropped it onto Noesis, F4 for backface culling,

doesn't look much worse, imho. But after reviewing I'd suggest using strips.

Noesis_Vi51f4SsSh.png

Edited by shak-otay

  • Author
  • Localization
12 minutes ago, shak-otay said:

Low poly models usually don't raise that big interest but the mesh format shouldn't be a big obstacle, or should it?

corolla-sgc.png

edit: didn't know whether triangle strips is the best choice here. Saved with normal triangles, drag&dropped it onto Noesis, F4 for backface culling,

doesn't look much worse, imho. But after reviewing I'd suggest using strips.

Noesis_Vi51f4SsSh.png

Same goes for characters (.SGS files), right? I know @Karpati already reversed the car model formats but not the character stuff iirc.

  • Supporter
25 minutes ago, huckleberrypie said:

Same goes for characters (.SGS files), right? I know @Karpati already reversed the car model formats

Dunno. If I had known the cars have already been reversed I'd checked the character SGS instead.

  • Author
  • Localization
2 minutes ago, shak-otay said:

Dunno. If I had known the cars have already been reversed I'd checked the character SGS instead.

Sorry about that. What I do know is that both share more or less the same structure but .SGS has skeletal model information. I could open some of the more simpler ones in Zmodeler 2 e.g. a can of Red Bull but not the human characters themselves.

  • Author
  • Localization
25 minutes ago, shak-otay said:

Char mesh format looks simple. For the skeleton you could try use Durik's skelfinder, read two posts here.

Index and vertex buffer locations seem straightforward, but finding the stride and count is a little confusing for me.

  • Supporter

"stride" (or FVFsize in hex2obj) is a multiple of 4 for float based formats. Using vertex start address 0x3f94 (type in 3f94 without the 0x) for mechanic-1-4_01.sgs and trying 12 in a first step and pressing the go2 button you'll see "NORM" in each 2nd line in the lower left window. This means the FVFsize is 24 in this case.

The vertexcount is calculated automatically (see lower left window) after pressing the go1 button. Provided you set the correct start address and FI count of the FI block. That's just a matter of experience. Or simply divide sizeOfVertex block by FVFsize. Works in most cases.

Edited by shak-otay

  • Supporter

Struct of SGS/SGC is pretty much same...

Here's some info...

//------------------------------------------------
//--- 010 Editor v14.0 Binary Template
//
//      File: 
//   Authors: 
//   Version: 
//   Purpose: 
//  Category: 
// File Mask: 
//  ID Bytes: 
//   History: 
//------------------------------------------------
LittleEndian();OutputPaneClear();

local uint32 i,j,k,l,TotalSize=FileSize();

string Sign;

struct
{
    do
    {
        struct 
        {
            uint32 ResourceSign;
            enum <uint32>
            {
                Mesh = 0,
                Bone = 3,
                Material = 5,
                MaterialEffect = 15,
                Skeleton = 18,
            }ResourceType;
            uint32 Unknown_2;
            uint32 Unknown_3;
            uint32 ResourceSize;
            local uint32 ResourceInfoEndOffset=FTell();
            byte ResourceData[ResourceSize];
            local uint32 cPos=FTell();
        }ResourceInfo;
    }
    while (ResourceInfo.ResourceSign == 12 & ResourceInfo.cPos != TotalSize);
}ResourceTable;

EDiT: Now you can dump it with this bms script.

###################################
get BaseFileName basename
get FileSize asize
get Sign string

do
	get ResourceSign uint32
	get ResourceType uint32
	get Unknown_2 uint32
	get Unknown_3 uint32
	get ResourceSize uint32
	savepos ResourceOffset
	getdstring ResourceData ResourceSize
	savepos cPos
	
	if ResourceType == 0
		set Extension string "mesh"
	elif ResourceType == 3
		set Extension string "bone"
	elif ResourceType == 5
		set Extension string "material"
	elif ResourceType == 15
		set Extension string "materialEffect"
	elif ResourceType == 18
		set Extension string "skeleton"
	else
		set Extension uint32 ResourceType
	endif
	
	string FileName p= "%s/%u.%s" BaseFileName ResourceOffset Extension
	log FileName ResourceOffset ResourceSize
while ResourceSign == 12 & cPos != FileSize

 

Edited by h3x3r

  • Author
  • Localization
11 hours ago, h3x3r said:

Struct of SGS/SGC is pretty much same...

Here's some info...

//------------------------------------------------
//--- 010 Editor v14.0 Binary Template
//
//      File: 
//   Authors: 
//   Version: 
//   Purpose: 
//  Category: 
// File Mask: 
//  ID Bytes: 
//   History: 
//------------------------------------------------
LittleEndian();OutputPaneClear();

local uint32 i,j,k,l,TotalSize=FileSize();

string Sign;

struct
{
    do
    {
        struct 
        {
            uint32 ResourceSign;
            enum <uint32>
            {
                Mesh = 0,
                Bone = 3,
                Material = 5,
                MaterialEffect = 15,
                Skeleton = 18,
            }ResourceType;
            uint32 Unknown_2;
            uint32 Unknown_3;
            uint32 ResourceSize;
            local uint32 ResourceInfoEndOffset=FTell();
            byte ResourceData[ResourceSize];
            local uint32 cPos=FTell();
        }ResourceInfo;
    }
    while (ResourceInfo.ResourceSign == 12 & ResourceInfo.cPos != TotalSize);
}ResourceTable;

EDiT: Now you can dump it with this bms script.

###################################
get BaseFileName basename
get FileSize asize
get Sign string

do
	get ResourceSign uint32
	get ResourceType uint32
	get Unknown_2 uint32
	get Unknown_3 uint32
	get ResourceSize uint32
	savepos ResourceOffset
	getdstring ResourceData ResourceSize
	savepos cPos
	
	if ResourceType == 0
		set Extension string "mesh"
	elif ResourceType == 3
		set Extension string "bone"
	elif ResourceType == 5
		set Extension string "material"
	elif ResourceType == 15
		set Extension string "materialEffect"
	elif ResourceType == 18
		set Extension string "skeleton"
	else
		set Extension uint32 ResourceType
	endif
	
	string FileName p= "%s/%u.%s" BaseFileName ResourceOffset Extension
	log FileName ResourceOffset ResourceSize
while ResourceSign == 12 & cPos != FileSize

 

What about a Noesis script?

I am able to figure out where the vertices are and more or less the count but the faces are a clincher to get.

Screenshot (786).png

Edited by huckleberrypie

  • Author
  • Localization
2 hours ago, shak-otay said:

Faces are simple for the mentioned mechanics:

mechanic.png

Got it now, thanks!

Screenshot (793).png

EDIT: There's one problem tho: I don't get any UVs for some reason.

Edited by huckleberrypie

  • Author
  • Localization
37 minutes ago, shak-otay said:

0xc4b4, UVB size 8

BAGbdUhnMx.png

Where do I enter that in the UV block?

  • Supporter

I have made a Noesis script but it's basic. Just simple mesh export. No materials/ no bones/ no skin.

Anyway this is mesh struct. Just basic.

//------------------------------------------------
//--- 010 Editor v14.0 Binary Template
//
//      File: 
//   Authors: 
//   Version: 
//   Purpose: 
//  Category: 
// File Mask: 
//  ID Bytes: 
//   History: 
//------------------------------------------------
LittleEndian();OutputPaneClear();

local uint32 i,j,k,l,TotalSize=FileSize();

string MeshName;
uint32 Unknown_0;
uint32 Unknown_1;
float Unknown_2[27];
float Unknown_3[5];
uint32 TotalVertexCount;
uint32 StrideType;
if (StrideType == 19)
{
    byte VertexBuffer[TotalVertexCount*24];
    byte ColorBuffer[TotalVertexCount*4];
}
else if (StrideType == 23)
{
    byte VertexBuffer[TotalVertexCount*24];
    byte UVBuffer[TotalVertexCount*8];
    byte ColorBuffer[TotalVertexCount*4];
}    
uint32 TotalIndexCount;
byte IndexBuffer[TotalIndexCount*6];

uint32 ShapeIndex;
struct 
{
    string MaterialName;
    uint32 IndexCount; // *3
    uint32 Unknown_0;
    uint32 VertexCount;
    uint32 Unknown_1;
}ShapeInfo[ShapeIndex]<optimize=false>;

FSeek(startof(VertexBuffer));

if (StrideType == 19)
{
    struct
    {
        float VPosX,VPosY,VPosZ,VNPosX,VNPosY,VNPosZ;
    }Vertices[TotalVertexCount]<optimize=false>;
}
else if (StrideType == 23)
{
    struct
    {
        float VPosX,VPosY,VPosZ,VNPosX,VNPosY,VNPosZ;
    }Vertices[TotalVertexCount]<optimize=false>;
    
    struct
    {
        float UVPosX,UVPosY;
    }UnitVector[TotalVertexCount]<optimize=false>;
}

FSeek(startof(IndexBuffer));

for (i=0; i < ShapeIndex; i++)
{
    struct
    {
        uint16 F1,F2,F3;
    }Indices[ShapeInfo[i].IndexCount]<optimize=false>;
    
}

image.thumb.png.df7e18aa58c0df16efda89fab83d450e.png

Edited by h3x3r

  • Author
  • Localization
1 hour ago, h3x3r said:

I have made a Noesis script but it's basic. Just simple mesh export. No materials/ no bones/ no skin.

Anyway this is mesh struct. Just basic.

//------------------------------------------------
//--- 010 Editor v14.0 Binary Template
//
//      File: 
//   Authors: 
//   Version: 
//   Purpose: 
//  Category: 
// File Mask: 
//  ID Bytes: 
//   History: 
//------------------------------------------------
LittleEndian();OutputPaneClear();

local uint32 i,j,k,l,TotalSize=FileSize();

string MeshName;
uint32 Unknown_0;
uint32 Unknown_1;
float Unknown_2[27];
float Unknown_3[5];
uint32 TotalVertexCount;
uint32 StrideType;
if (StrideType == 19)
{
    byte VertexBuffer[TotalVertexCount*24];
    byte ColorBuffer[TotalVertexCount*4];
}
else if (StrideType == 23)
{
    byte VertexBuffer[TotalVertexCount*24];
    byte UVBuffer[TotalVertexCount*8];
    byte ColorBuffer[TotalVertexCount*4];
}    
uint32 TotalIndexCount;
byte IndexBuffer[TotalIndexCount*6];

uint32 ShapeIndex;
struct 
{
    string MaterialName;
    uint32 IndexCount; // *3
    uint32 Unknown_0;
    uint32 VertexCount;
    uint32 Unknown_1;
}ShapeInfo[ShapeIndex]<optimize=false>;

FSeek(startof(VertexBuffer));

if (StrideType == 19)
{
    struct
    {
        float VPosX,VPosY,VPosZ,VNPosX,VNPosY,VNPosZ;
    }Vertices[TotalVertexCount]<optimize=false>;
}
else if (StrideType == 23)
{
    struct
    {
        float VPosX,VPosY,VPosZ,VNPosX,VNPosY,VNPosZ;
    }Vertices[TotalVertexCount]<optimize=false>;
    
    struct
    {
        float UVPosX,UVPosY;
    }UnitVector[TotalVertexCount]<optimize=false>;
}

FSeek(startof(IndexBuffer));

for (i=0; i < ShapeIndex; i++)
{
    struct
    {
        uint16 F1,F2,F3;
    }Indices[ShapeInfo[i].IndexCount]<optimize=false>;
    
}

image.thumb.png.df7e18aa58c0df16efda89fab83d450e.png

Would you mind sharing the script? Or are you still in the process of improving it?

  • Supporter

Nah no improvements so far and don't think there will be any...

from inc_noesis import *
import noesis
import rapi
import os

def registerNoesisTypes():
   handle = noesis.register("Richard Burns Rally - Geometry", ".mesh")
   noesis.setHandlerTypeCheck(handle, noepyCheckType)
   noesis.setHandlerLoadModel(handle, noepyLoadModel)
   noesis.logPopup()
   return 1
        
def noepyCheckType(data):
   bs = NoeBitStream(data)
   if len(data) < 20:
      return 0
   return 1
        
def noepyLoadModel(data, mdlList):
	bs = NoeBitStream(data)
	baseName = rapi.getExtensionlessName(rapi.getLocalFileName(rapi.getInputName()))
	ctx = rapi.rpgCreateContext()
	Underline = "_"
	MeshName = bs.readString()
	Unknown_0 = bs.readUInt()
	Unknown_1 = bs.readUInt()
	bs.read(128)
	TotalVertexCount = bs.readUInt()
	StrideType = bs.readUInt()
	if StrideType == 19:
	    VertexBuffer = bs.read(TotalVertexCount * 24)
	    ColorBuffer = bs.read(TotalVertexCount * 4)
	elif StrideType == 23:
	    VertexBuffer = bs.read(TotalVertexCount * 24)
	    UnitVectorBuffer = bs.read(TotalVertexCount * 8)
	    ColorBuffer = bs.read(TotalVertexCount * 4)
        
	TotalIndexCount = bs.readUInt()
	IndexBufferBaseOffset = bs.tell()
	bs.read(TotalIndexCount * 6)
    
	if StrideType == 19:
	    rapi.rpgBindPositionBufferOfs(VertexBuffer, noesis.RPGEODATA_FLOAT, 24, 0)
	    rapi.rpgBindNormalBufferOfs(VertexBuffer, noesis.RPGEODATA_FLOAT, 24, 12)
	elif StrideType == 23:
	    rapi.rpgBindPositionBufferOfs(VertexBuffer, noesis.RPGEODATA_FLOAT, 24, 0)
	    rapi.rpgBindNormalBufferOfs(VertexBuffer, noesis.RPGEODATA_FLOAT, 24, 12)
	    rapi.rpgBindUV1BufferOfs(UnitVectorBuffer, noesis.RPGEODATA_FLOAT, 8, 0)
            
	ShapeIndex = bs.readUInt()
	IndexCountList = []
	MaterialNameList = []
    
	for i in range(0, ShapeIndex):
		MaterialNameList.append(bs.readString())
		IndexCountList.append(bs.readUInt()*3)
		Unknown_0 = bs.readUInt()
		VertexCount = bs.readUInt()
		Unknown_1 = bs.readUInt()
    
	bs.seek(IndexBufferBaseOffset, NOESEEK_ABS)
	for i in range(0, ShapeIndex):
		IndexCount = IndexCountList[i]
		MaterialName = MaterialNameList[i]
		IndexBuffer = bs.read(IndexCount * 2)
		ShapeIdDigfmt = "{:04d}".format(i)
		rapi.rpgSetName(MeshName + Underline + ShapeIdDigfmt)
		#rapi.rpgSetMaterial(MaterialName)
		rapi.rpgCommitTriangles(IndexBuffer, noesis.RPGEODATA_USHORT, IndexCount, noesis.RPGEO_TRIANGLE)
		mdl = rapi.rpgConstructModel()
	mdlList.append(mdl)
	return 1

You can try on your own 😉

  • Author
  • Localization
13 hours ago, shak-otay said:

0xc4b4, UVB size 8

BAGbdUhnMx.png

This is for Richard, right?

I tried the following values as shown in the screenshot and this is what I got:

Screenshot (794).png

  • Author
  • Localization
1 hour ago, shak-otay said:

Who is Richard?

I referred to mechanic-1-4_01.sgs.

I see.

Create an account or sign in to comment

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.