Okay, here's the layout of the RSM format as much as I can figure out:

- texture paths are relative to the Ragnarok folder.
- size specified as structure or data type or in bytes 
- structure sizes and content listed in type definitions below

Data/Field	Size				Notes
======================================================================================		
<HEADER>	
--------------------------------------------------------------------------------------
'GRSM'		4				RSM identifier/header
todo 		27				Unknown, labled "todo"
nTextures	int				Number of textures (int)
text_name	ro_string * nTextures		

<MESH>						Keep reading in a mesh until EOF or
						30 meshes are read in		
---------------------------------------------------------------------------------------
name		ro_string			name of mesh
todo		int				integer, only read for first mesh
parent_name	ro_string
ftodo		int * 10			Array of 10 floats, only read for first mesh
ntextures	int				number of textures for this mesh
n		int * ntextures			see code
transf		float * 22			used in transformations...

npos_vtx	int				number of vertices
pos_vtx		ro_vertex_t * npos_vtx		array of vertices

ntex_vtx	int				number of texture coordinates
tex_vtx 	ro_vertex_t * ntex_vtx		array of coordinates (see code)

nall_faces	int				number of faces
all_faces 	ro_face_t * nall_faces		array of face structures

nframes		int				number of frame animations
frames 		ro_frame_t * nframes		array of frame structures


So RSM layout is:
<HEADER>
<MESH>
<MESH>
 .
 .
 .
<MESH>

or usually just one mesh



Here's the code:
================
//Type definitions

typedef char ro_string_t[40];		// The RO path string, 40 bytes wide

typedef struct {			// RSM Header
	char filecode[4];		
	char todo[27];
} rsm_header_t;

typedef struct {			// Used by app to store position information
	GLfloat x;
	GLfloat y;
	GLfloat z;
	GLfloat rx;
	GLfloat ry;
	GLfloat rz;
	GLfloat sx;
	GLfloat sy;
	GLfloat sz;
} ro_position_t;

typedef float ro_vertex_t[3];		// Stores vertex information

typedef struct {
	short v[3];			// Indexed vertices to use for this face
	short t[3];			// Indexed texture coordinates to use for this face
	unsigned short	  text;		// Which texture to use for this surface
	unsigned short	todo1;		// ???
	unsigned int   todo2;		// ???
	unsigned int   nsurf;		// ???
} ro_face_t;

typedef struct {
	unsigned int text;	// Which texture to use for this surface
	int nvertex;		// Number of Vertexes 
	int nfaces;		// Number of Faces/Triangles
	gl_vertex_t *vertex;	
	gl_face_t *faces;
} ro_surface_t;

typedef struct {
	GLfloat todo[22];	// ???
} ro_transf_t;

typedef float ro_quat_t[4];

typedef struct {
	int time;
	ro_quat_t orientation;
} ro_frame_t;

typedef struct {
	GLfloat max[3];
	GLfloat min[3];
	GLfloat range[3];
} bounding_box_t;

//Classes
class RSM  
{
public:
	RSM();							// Constructor
	bool Load(char *ragnapath, char *filename);		// RSM Loader
	void Display(ro_position_t pos);			
	void DisplayMesh(bounding_box_t *b, int n, ro_transf_t *ptransf=NULL);
	virtual ~RSM();

private:
	void BoundingBox();

private:
	bounding_box_t box;
	int *father;
	GLfloat range[3];
	GLfloat min[3];
	GLfloat max[3];
	rsm_header_t header;
	int nmeshes;
	RSM_Mesh *meshes;
	int ntextures;
	GLuint *textures;
	ro_string_t *textures_name;
	bool *alphatex;
};


class RSM_Mesh  
{
public:
	RSM_Mesh();
	bool Load(FILE *fp, GLuint *all_textures, bool *alphatex, bool main);
	void Display(bounding_box_t *box, ro_transf_t *ptransf = NULL);
	virtual ~RSM_Mesh();
	ro_transf_t transf;
	ro_vertex_t *pos_vtx;
	GLfloat range[3];
	GLfloat min[3];
	GLfloat max[3];
	void BoundingBox(ro_transf_t *ptransf=NULL);
	ro_string_t	name;
	ro_string_t parent_name;
	bool only;

private:


//Parsing
bool RSM::Load(char *ragnapath, char *filename)
{
	FILE *fp;
	int i;

	fp = fopen(filename, "rb");

	if (!fp) {
		return false;
	}

	//Read in the header
	fread (&header, sizeof(rsm_header_t), 1, fp);
	
	//Get the number of textures
	fread (&ntextures, sizeof(int), 1, fp);

	textures = new GLuint[ntextures];
	alphatex = new bool[ntextures];
	textures_name = new ro_string_t[ntextures];

	//Read texture paths into an array of strings 40 bytes wide each...
	fread (textures_name, sizeof(ro_string_t), ntextures, fp);

	//prepare textures for openGL
	glGenTextures(ntextures, textures);

	//Load textures
	for (i = 0; i < ntextures; i++)
		LoadTexture (ragnapath, textures_name[i], textures[i], &alphatex[i]);
	
	meshes = new RSM_Mesh[30];

	//Read in mesh structure until we hit end-of-file or 30 meshes
	while (file_status(fp) != 0) {
		meshes[nmeshes].Load(fp, textures, alphatex, (nmeshes == 0));
		nmeshes++;
		if (nmeshes > 29)
			break;
	}

	if (nmeshes == 1)
		meshes[0].only = true; 	//Set if only one mesh was read...
	else
		meshes[0].only = false;
	fclose (fp);

	//create mesh heirarchy
	father = new int[nmeshes];
	father[0] = 0;
	for (i = 0; i < nmeshes; i++)
		for (int j = 0; j < nmeshes; j++)
			if ((j != i) && (!strcmp(meshes[j].parent_name, meshes[i].name)))
				father[j] = i;

	BoundingBox();		//Set up bounding box

	return true;
}



AUX_RGBImageRec *LoadBMP(char *Filename)
{
  FILE *File=NULL;	
  
  if (!Filename)	
    {
      return NULL;	
    }

  File=fopen(Filename,"r");
  
  if (File)		
    {
      fclose(File);			
      return auxDIBImageLoad(Filename);
    }
  
  return NULL;
}

#define coord3(t, x, y, o) t[3*((x)+(y)*w)+o] 
#define coord4(t, x, y, o) t[4*((x)+(y)*w)+o] 

bool LoadTexture(char *ragnapath, char *filename, GLuint texture, bool *alpha)
{
	int h, w, j, k;
	unsigned char *cdata;
	unsigned char *ndata;
	char buffer[512];
	int l;
	l = strlen(filename);

	sprintf (buffer, "%s\\data\\texture\\%s", ragnapath, filename);

	if ((filename[l-3] == 'b' && 
		filename[l-2] == 'm' &&
		filename[l-1] == 'p') || (filename[l-3] == 'B' && 
		filename[l-2] == 'M' &&
		filename[l-1] == 'P')) {

	AUX_RGBImageRec *image;
	image = LoadBMP(buffer);
	if(!image) image = LoadBMP("blank.bmp");
	h = image->sizeY;
    	w = image->sizeX;

      cdata = (unsigned char *) image->data;
      ndata = (unsigned char *) malloc (sizeof(unsigned char)*4*h*w);

    for (j = 0; j < h; j++) 
      for (k = 0; k < w; k++) {
      unsigned char a, r, g, b;

      b = coord3(cdata, k, h-1-j, 0);
      g = coord3(cdata, k, h-1-j, 1);
      r = coord3(cdata, k, h-1-j, 2);

      ndata[4*(j*w+k)] = b;
      ndata[4*(j*w+k)+1] = g;
      ndata[4*(j*w+k)+2] = r;
      if (g==0 && r>253 && b>253)
		ndata[4*(j*w+k)+3] = 0;
      else
		ndata[4*(j*w+k)+3] = 255;
    }

    glBindTexture(GL_TEXTURE_2D, texture);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	gluBuild2DMipmaps ( GL_TEXTURE_2D, GL_RGBA, w, h,
		GL_RGBA, GL_UNSIGNED_BYTE, ndata );

		if (alpha)
			*alpha = false;
	} else if ((filename[l-3] == 't' &&
		filename[l-2] == 'g' &&
		filename[l-1] == 'a') || (filename[l-3] == 'T' &&
		filename[l-2] == 'G' &&
		filename[l-1] == 'A')) {


		image_t   p;

	    glBindTexture(GL_TEXTURE_2D, texture);
	    tgaLoad  ( buffer, &p, TGA_NO_PASS);

    h = p.info.height;
    w = p.info.width;

    cdata = (unsigned char *) p.data;
    ndata = (unsigned char *) malloc (sizeof(unsigned char)*4*h*w);

    for (j = 0; j < h; j++) 
      for (k = 0; k < w; k++) {
      unsigned char a, r, g, b;

      r = coord4(cdata, k, h-1-j, 0);
      g = coord4(cdata, k, h-1-j, 1);
      b = coord4(cdata, k, h-1-j, 2);
      a = coord4(cdata, k, h-1-j, 3);

      ndata[4*(j*w+k)] = r;
      ndata[4*(j*w+k)+1] = g;
      ndata[4*(j*w+k)+2] = b;
	  ndata[4*(j*w+k)+3] = a;
    }

		char buf[512];
		sprintf(buf, "%d\n", p.info.tgaColourType);
	//	MessageBox(NULL, buf, NULL, 0);

	    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);

	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

		gluBuild2DMipmaps ( GL_TEXTURE_2D, p.info.tgaColourType, p.info.width,
                  p.info.height, p.info.tgaColourType, GL_UNSIGNED_BYTE, ndata );

		if (alpha)
			*alpha = true;
	} else {
		MessageBox (NULL, "Unknown texture type", "Error", 0);
		return false;
	}

	return true;
}


bool RSM_Mesh::Load(FILE *fp, GLuint *all_textures, bool *all_alphatex, bool main)
{
	int i;
	char buffer[1024];
	int *surfnum;
	FILE *fout;

	//Get the name of this mesh
	fread (name, sizeof(ro_string_t), 1, fp);
	
	if (main)
		fread (&todo, sizeof(int), 1, fp);

	fread (parent_name, sizeof(ro_string_t), 1, fp);

	if (main)
		fread (ftodo, sizeof(float), 10, fp);

	fread (&ntextures, sizeof(int), 1, fp);

	textures = new GLuint[ntextures];
	alphatex = new bool[ntextures];
	which = new int[ntextures];

	for (i = 0; i < ntextures; i++) {
		int n;
		fread (&n, sizeof(int), 1, fp);
		which[i] = n;
		textures[i] = all_textures[n];
		alphatex[i] = all_alphatex[i];
	}

	fread (&transf, sizeof(ro_transf_t), 1, fp);

	fread (&npos_vtx, sizeof(int), 1, fp);
	pos_vtx = new ro_vertex_t[npos_vtx];
	fread (pos_vtx, sizeof(ro_vertex_t), npos_vtx, fp);

	fread (&ntex_vtx, sizeof(int), 1, fp);
	tex_vtx = new ro_vertex_t[ntex_vtx];
	fread(tex_vtx, sizeof(ro_vertex_t), ntex_vtx, fp);

	fread(&nall_faces, sizeof(int), 1, fp);
	all_faces = new ro_face_t[nall_faces];
	fread (all_faces, sizeof(ro_face_t), nall_faces, fp);

	if (file_status(fp) != 2) {
		return true;
	}

	fread (&nframes, sizeof(int), 1, fp);
	frames = new ro_frame_t[nframes];
	fread (frames, sizeof(ro_frame_t), nframes, fp);

	return true;
}



void RSM_Mesh::BoundingBox(ro_transf_t *ptransf)
{
	int main = (ptransf == NULL);
	GLfloat Rot[16];
	GLfloat *Transf;
	int i;
	int j;
	int k;
	GLfloat pmax[3], pmin[3];

	Rot[0] = transf.todo[0];
	Rot[1] = transf.todo[1];
	Rot[2] = transf.todo[2];
	Rot[3] = 0.0;

	Rot[4] = transf.todo[3];
	Rot[5] = transf.todo[4];
	Rot[6] = transf.todo[5];
	Rot[7] = 0.0;

	Rot[8] = transf.todo[6];
	Rot[9] = transf.todo[7];
	Rot[10] = transf.todo[8];
	Rot[11] = 0.0;

	Rot[12] = 0.0;
	Rot[13] = 0.0;
	Rot[14] = 0.0;
	Rot[15] = 1.0;

	max[0] = max[1] = max[2] = -999999.0;
	min[0] = min[1] = min[2] = 999999.0;

	for (i = 0; i < npos_vtx; i++) {
		GLfloat vtemp[3], vout[3];

		MatrixMultVect(Rot, pos_vtx[i], vout);
		for (j = 0; j < 3; j++) {
			GLfloat f;
			if (!only)
				f = vout[j]+transf.todo[12+j]+transf.todo[9+j];
			else
				f = vout[j];

			min[j] = MIN(f, min[j]);
			max[j] = MAX(f, max[j]);
		}
	}

	for (j=0; j < 3; j++)
		range[j] = (max[j]+min[j])/2.0;
}

