Home | Download | Discussion | Help | Site Map | New Posts | Sign in

Latest Site News

Community Spirit contest! - posted on 11th Apr 2017 at 6:33 PM
Replies: 27 (Who?), Viewed: 3959 times.
Page 1 of 2
MakeNeedsStaticOn
staff: moderator
Original Poster
#1 Old 10th Jun 2016 at 9:11 PM
Default How to add a geostate as a regular mesh?
As I was converting a new the sims 2 to the sims 3 set, and was going to convert this bonfire: http://sims.wikia.com/wiki/Campfire (The 'Stack-O-Flames Bonfire one). I noticed when I exported the mesh from SimPE it had 3 different meshes. And I thought it was a pretty nice thing to have it since the sims 3 uses geostates.

But now I'm encountering the problem that I didn't thought of when I exported the mesh.

How do you import a mesh to a geostate? I know that you usually have to select the faces of the meshes you want to be visible, but I was wondering if you somehow can add a geostate to the mesh with S3PE or maybe even a notepad?

Did anyone ever succeeded doing it? I noticed S3PE exports the geostates as a S3ACG instead of a S3AC. Is there a way to merge them together to make S3PE see it as an actual mesh with geostates?
Advertisement
Alchemist
#2 Old 11th Jun 2016 at 3:01 AM
Arsil's talking about Geostates and S3PE in this thread, if it helps at all: http://modthesims.info/t/553279
MakeNeedsStaticOn
staff: moderator
Original Poster
#3 Old 11th Jun 2016 at 1:53 PM
Quote:
Originally Posted by murfee
Arsil's talking about Geostates and S3PE in this thread, if it helps at all: http://modthesims.info/t/553279


Hmmm that got me closer to my answer, yet I have nooo idea how to add a different mesh as geostate. I'll let you know if I somehow found a way to do it ^-^
Test Subject
#4 Old 3rd Jul 2016 at 4:48 PM
The best way to get a new mesh into a geostate is probably to add a new group to the MLOD of the object you wish to use as a base, and then make your new object with one geostate mesh and one empty geostate per group.

Step 1: Add a new group
In S3PE use the grid view to navigate to ChunkEntries > [00] ChunkEntries > RCOLBlock > Meshes (Collection : 0x02)
Now click the "..." button to bring up a new DataGrid window for the Meshes
Select [0] Mesh and click the "Copy" button
This will duplicate the [0] mesh as [2] Mesh, keeping all the material references intact
Click "OK" to close the secondary DataGrid window and you will see that the main window now displays Meshes (Collection : 0x03)
Click "Commit" to update the MLOD and save your object under a new name.

Step 2:
Make new meshes in Mikshape and assign each to its own group

Step 3
Export the meshes as S3ACG, which will give you one S3AC placeholder and two S3ACG files

Step 4
Import the new meshes into the object you made in Step 1

Step 5
Set up the geostates for each mesh group.
As noted in the other thread, http://modthesims.info/t/553279 , it is perfectly OK for an MLOD to have the same geostates in more than one mesh group.
If the geostate in one mesh group has face count = 0 and vertex count = 0, then none of the faces in that mesh group show up when that geostate is active.

So for a simple example with two geostates (and a default state which is never visible outside TSRW)
One group uses the whole [0] mesh for geostate A, and geostate B has face count = 0 and vertex count = 0
The other group uses the whole [2] mesh for geostate B, and geostate A has face count = 0 and vertex count = 0

Hope this helps

Peter
Field Researcher
#5 Old 19th Jul 2016 at 3:01 AM
@peter9g

Sorry for butting in, but I'm wondering: can multiple geostates in the same mesh group have "overlapping" primitives/vertices? For example, with a fruit bowl where the fruit and the bowl are in the same mesh group, is it possible to have geostate A be the bowl alone, and geostate B be the bowl & fruit together?

I've added new geostates to an object with S3PE, setting all the geostates to show all the faces in the mesh group temporarily, so that they can be edited in Blender. They appear correctly in S3PE's MLOD Preview. When Blender imports the mesh, however, TS3 Tools throw an error about something being out of range for an array and its Geostate Editor does not display the new geostates. The outliner only shows one of the geostates, likely because the import was partially dropped.

Thanks!
MakeNeedsStaticOn
staff: moderator
Original Poster
#6 Old 19th Jul 2016 at 11:57 AM
I think I saw the same exact thing with the 'Causestatueeffect' which is pretty much the legacy statues from the sims 3 ITF.

I'm not sure if you had any issues with Blender and it's ts3 tools, but I can't seem to like it as much as I want since it keeps throwing errors. So I usually work my way around. >-< Though, I've noticed the tool has 2 plugins that you need to enable in Blender itself. Maybe that's where it goes wrong?
Field Researcher
#7 Old 20th Jul 2016 at 10:55 AM
The plugins are enabled in Blender, otherwise they would not appear in the UI at all, I think. Anyway, these errors only occur if the MLOD that's being imported into Blender already has modder-added geostates set up. These Blender import errors do not appear if the modder-added geostates are set up with only 0 as values, but after editing the mesh and exporting from Blender, S3PE will throw an error on import, even though the geostates were initially added there.

So far, I have not found a way to make newly added geostates (i.e. geostates added to objects that didn't originally contain geostates) round-trip properly through Blender. I suspect it has something to do with mismatches in the primitive indices, but this is pure conjecture ATM. However, the good news is that entirely new geostates can be implemented (i.e. in objects that didn't contain geostates originally) using a combination of Blender and S3PE alone, provided that the geostate meshes are set up as mesh groups, and that the actual geostates themselves are added at the end in S3PE, once the meshes have been finalized, to avoid transiting them through Blender. This provides the advantage that 1) TSRW is not needed for people who have trouble running it and 2) geostates can be added to objects that did not have any before (AFAIK, TSRW only allows editing of existing geostates or adding geostates by duplicating an existing one, which cannot be done if an object contains no geostate to begin with.)
MakeNeedsStaticOn
staff: moderator
Original Poster
#8 Old 20th Jul 2016 at 2:58 PM
You're right when it comes to TSRW not allowing to add geostates to an objects that doesn't have any. Yet, say you're cloning an bookcase, TSRW's way is very hard. You need to click every. single. face that you want to show in another geostate. Which is pretty unhelpful when it comes to bonfires like I described.
So, TSRW... it's a great program, just not for geostates, especially like a dollhouse or a bonfire. which makes the method that Peter9g explained actually really helpful. I would have done it with Blender too but it just appear to be extremely buggy for me. I actually never imported a Geostate back in Blender so I can't really tell if it's just that, but from my experience, it keeps throwing error, even if I want to import something really simple. I normally need to work my way around.

But I guess it should work just the same way whether you use Blender or milkshape.

Just a question. Say you're baking a multiplier inside Blender, does your blender gives you this transparent texture? I had tht issue and it appeared that the plugin stays there after you seem to unable it. It's weird because I never managed to enable it the correct way, especially in blender 2.7+ but I can't really remember which plugin I enabled to make it work properly, actually.
Field Researcher
#9 Old 21st Jul 2016 at 1:43 AM
Quote:
Originally Posted by Greenplumbbob
So, TSRW... it's a great program, just not for geostates, especially like a dollhouse or a bonfire. which makes the method that Peter9g explained actually really helpful. I would have done it with Blender too but it just appear to be extremely buggy for me. I actually never imported a Geostate back in Blender so I can't really tell if it's just that, but from my experience, it keeps throwing error, even if I want to import something really simple. I normally need to work my way around. [...] But I guess it should work just the same way whether you use Blender or milkshape.


If you make new mesh groups just by duplicating an existing mesh group in S3PE, Blender will throw an error on import, even without geostates present. To prevent that, a couple of small things should be done in S3PE beforehand, then Blender will import the newly added mesh groups without problem. I could do a write-up on this, since no one seems to be doing it this way, but I don't know if anybody is interested.

I use Milkshape too, for CAS parts, since the meshes are simpler in terms of geometry (so Milkshape's limited selection + editing toolset is not as much of a pain point), but more temperamental when it comes to bones, etc.

Quote:
Originally Posted by Greenplumbbob
Just a question. Say you're baking a multiplier inside Blender, does your blender gives you this transparent texture? I had tht issue and it appeared that the plugin stays there after you seem to unable it. It's weird because I never managed to enable it the correct way, especially in blender 2.7+ but I can't really remember which plugin I enabled to make it work properly, actually.


I've bake multipliers, masks, and specular maps in Blender 2.70 successfully. I don't recall getting a transparent/blank image. The only thing that needs to be enabled for this is io_TS3_tools.py (under Import-Export: Sims 3 MLOD/MODL Tools in Blender User Preferences.)
Test Subject
#10 Old 21st Jul 2016 at 2:00 AM
Quote:
Originally Posted by Butterbot
@peter9g

Sorry for butting in, but I'm wondering: can multiple geostates in the same mesh group have "overlapping" primitives/vertices? For example, with a fruit bowl where the fruit and the bowl are in the same mesh group, is it possible to have geostate A be the bowl alone, and geostate B be the bowl & fruit together?

I've added new geostates to an object with S3PE, setting all the geostates to show all the faces in the mesh group temporarily, so that they can be edited in Blender. They appear correctly in S3PE's MLOD Preview. When Blender imports the mesh, however, TS3 Tools throw an error about something being out of range for an array and its Geostate Editor does not display the new geostates. The outliner only shows one of the geostates, likely because the import was partially dropped.

Thanks!


Hi Butterbot

It is possible for multiple geostates in the same mesh group have "overlapping" primitives/vertices.
The EA bookcases do this so that geostate A can be the bookcase, B can be the bookcase with a few books and C can be the bookcase full of books.
However we do not have the tools that EA does, and as Greenplumbob notes it is painful to try to subtract polygons in TSRW to make a new geostate.
i.e start with state C and subtract books to make states A and B

It is also potentially inefficient, if the mesh data in the MLOD does not keep the disappearing pieces together where they can be turned on or off by changing the Index and VerteBufferOffsets.

AS a quick example I added another geostate to the dollhouse by duplicating the DollhouseUpright geostate, then turned off a bunch of polygons in TSRW.
There is no way that TSRW could store the information as to which polygons I turned off in the third geostate without writing out a new polygon list.
So the original dollhouse has an IBUF chunk of 0x21A6 bytes; the dollhouse with the third edited geostate has an IBUF chunk of 0x4A32 bytes

It makes a lot of sense then to model your fruit bowl example as two mesh groups
group 0 = bowl: geostate A = geostate B
group 1 = fruit: geostate A is empty, and geostate B is the fruit.

For a real life example see Pocci's WireMeshBookshelf, which is cloned from the basegame BookshelfStudentHigh, with an extra mesh group so that the bookshelf is in group 0 and common to all geostates, while the books are in the new mesh group.

Hope this helps

Peter
Field Researcher
#11 Old 21st Jul 2016 at 2:47 AM
Hi Peter,

Thanks for your detailed reply. So it seems that, without EA's toolset, the best course is to separate the static parts of the mesh from the parts that change according to geostate. Otherwise, the polycount mounts quickly because the IBUF entries for the static faces are duplicated with each geostate. Helpful to know--thanks again!
Field Researcher
#12 Old 24th Jul 2016 at 5:01 AM
@Greenplumbbob

Quote:
Originally Posted by Greenplumbbob
Just a question. Say you're baking a multiplier inside Blender, does your blender gives you this transparent texture?


I sort of ran into a similar issue for the first time today, while baking an RGB mask with 4 channels (3-channel masks seem OK). There were a couple of problems:

1. The alpha transparency seems to be randomly assigned to the channels and not always confined to the 4th channel. For example, in the Image Editor, parts of the mask affecting faces associated with the red or green channels can be displayed as transparent at the same time, which should not occur. Depending on how the UV is organized, it could look like the entire image is transparent.

2. When the mask image is saved, the transparency seems "hard baked" into the RGB channels, instead of being in a separate alpha channel. This occurs even if the views from the 3 small "Channels of the Image to Draw" buttons in the header of the Image Editor are correct. I've tried all the suggestions online of exporting to RBGA (PNG or TIFF), changing the Alpha option under Shading in the Render options to "Transparent with Premulitplied Alpha" instead of Sky, and making a new image in the Image Editor with the colour alpha set to 0. I've even tried baking with the native bake function in Blender, to no avail.

The workaround I've found for this so far is to export the mask twice, the second time with the alpha inverted in Image Editor, then re-assembling the whole thing and isolating the alpha channel manually in Photoshop. I'm stumped for now!
MakeNeedsStaticOn
staff: moderator
Original Poster
#13 Old 26th Jul 2016 at 12:08 PM
Quote:
Originally Posted by Butterbot
@Greenplumbbob



I sort of ran into a similar issue for the first time today, while baking an RGB mask with 4 channels (3-channel masks seem OK). There were a couple of problems:

1. The alpha transparency seems to be randomly assigned to the channels and not always confined to the 4th channel. For example, in the Image Editor, parts of the mask affecting faces associated with the red or green channels can be displayed as transparent at the same time, which should not occur. Depending on how the UV is organized, it could look like the entire image is transparent.

2. When the mask image is saved, the transparency seems "hard baked" into the RGB channels, instead of being in a separate alpha channel. This occurs even if the views from the 3 small "Channels of the Image to Draw" buttons in the header of the Image Editor are correct. I've tried all the suggestions online of exporting to RBGA (PNG or TIFF), changing the Alpha option under Shading in the Render options to "Transparent with Premulitplied Alpha" instead of Sky, and making a new image in the Image Editor with the colour alpha set to 0. I've even tried baking with the native bake function in Blender, to no avail.

The workaround I've found for this so far is to export the mask twice, the second time with the alpha inverted in Image Editor, then re-assembling the whole thing and isolating the alpha channel manually in Photoshop. I'm stumped for now!


I actually just came across this page: http://simswiki.info/wiki.php?title...Object_Creation
It seems to have a tool that creates sims 3 alpha channels. or just... Alpha channels in general.

The issue I had was basically with the multiplier and specular to be all transparent. I'm not sure if I should have run the tool with an image already attached to the UV map (like regular baking). Yet I can't still really find out how I made it work with the 2.76 version of Blender. Usually I don't bake my textures at all, but for objects it's pretty helpful.
MakeNeedsStaticOn
staff: moderator
Original Poster
#14 Old 26th Jul 2016 at 1:22 PM
I'm getting the hang of it, although it seems that i'm not quite sure how the 'model switching' goes when it comes to bonfires.

So this is how it should look like:



And this is how they look like in TSRW after even changing the facecount and vertexcount:







So I suppose I do need to play around with the Index and VerteBufferOffsets a bit?
Field Researcher
#15 Old 26th Jul 2016 at 9:26 PM
Quote:
Originally Posted by Greenplumbbob
I actually just came across this page: http://simswiki.info/wiki.php?title...Object_Creation
It seems to have a tool that creates sims 3 alpha channels. or just... Alpha channels in general.


You mean DXTBmp (it's linked to in the tutorial)? Is there another link I missed?

DXTBmp seems to edit alpha channels, not make new ones from the mesh/UV. Editing is no problem (I do that in Photoshop); the issue is that the alpha channel is not exported at all when saving the mask in Blender's Image Editor. When the resulting image is opened in Photoshop, there's no alpha channel, just RGB.

Quote:
Originally Posted by Greenplumbbob
I'm not sure if I should have run the tool with an image already attached to the UV map (like regular baking). Yet I can't still really find out how I made it work with the 2.76 version of Blender.


The instructions for the Blender TS3 Tools only say to have the UV/Image Editor open and to select the specific groups you want to bake. These steps worked for me. Could you be seeing problems because the Tools only support up to Blender 2.70?

Regarding the bonfire, did you do those geostates in the Blender TS3 Tools' Geostate Editor? That doesn't seem to work at all (I posted about it here.) But I've had success setting up the different states first as new mesh groups in S3PE, editing the meshes in Blender, then setting up the geostates themselves (StartIndex, MinVertexIndex,VertexCount, and PrimitiveCount) in S3PE, as broadly suggested by peter9g.
MakeNeedsStaticOn
staff: moderator
Original Poster
#16 Old 27th Jul 2016 at 11:50 AM
Yep that's the one I meant. I actually needed it for other purposes, yet I haven't tried it out yet. But as I took a break from meshing and all, I started to realise it might not support (or create) Alpha channels. I usually make them in Photoshop too so I guess that's the best way to do it.

About the geostates, I cloned the bonfire through S3OC (Since I don't trust TSRW in these kinds of things). So I think that wasn't really necessary, especially since the sims 2 bonfire has the same amount of meshes needed for the geostates like the University bonfire.
The stupid thing I did was Merging the groups together instead of assigning them to a new group. With groups, is it like group00 or group01, etc? Or something completely different? though I guess this already answers my question:

group 0 = bowl: geostate A = geostate B
group 1 = fruit: geostate A is empty, and geostate B is the fruit.

The only thing that's a bit confusing for me is the IBUF Chunk part. Is it a bit like 'switching' meshes? (Like the gnomes, yet those work with instances and the script telling it to switch).
Field Researcher
#17 Old 28th Jul 2016 at 12:51 PM
Quote:
group 0 = bowl: geostate A = geostate B
group 1 = fruit: geostate A is empty, and geostate B is the fruit.


In my current project, it seems that if a mesh group is always visible, it doesn't need geotates at all. For instance, in this example, the bowl is always visible--the only mesh group that changes is the fruit (empty bowl vs full bowl), so only the fruit mesh group needs geostates.

I'm not familiar with the gnome. But even with geostates, it's the scripting class that does the switching.
MakeNeedsStaticOn
staff: moderator
Original Poster
#18 Old 29th Jul 2016 at 11:04 PM
I might actually take a look at the Dollhouse since that one switches models in a way. (well... that's what Geostates do, but to get a better understanding in the IBUF files) and edit the files from there I guess and take use peter's post as 'guide'.

I'll let you know if it's going to work out.
Forum Resident
#19 Old 1st Aug 2016 at 2:28 AM Last edited by olomaya : 1st Aug 2016 at 3:22 AM.
Quote:
Originally Posted by peter9g
The best way to get a new mesh into a geostate is probably to add a new group to the MLOD of the object you wish to use as a base, and then make your new object with one geostate mesh and one empty geostate per group.

Step 1: Add a new group
In S3PE use the grid view to navigate to ChunkEntries > [00] ChunkEntries > RCOLBlock > Meshes (Collection : 0x02)
Now click the "..." button to bring up a new DataGrid window for the Meshes
Select [0] Mesh and click the "Copy" button
This will duplicate the [0] mesh as [2] Mesh, keeping all the material references intact
Click "OK" to close the secondary DataGrid window and you will see that the main window now displays Meshes (Collection : 0x03)
Click "Commit" to update the MLOD and save your object under a new name.

Step 2:
Make new meshes in Mikshape and assign each to its own group

Step 3
Export the meshes as S3ACG, which will give you one S3AC placeholder and two S3ACG files

Step 4
Import the new meshes into the object you made in Step 1

Step 5
Set up the geostates for each mesh group.
As noted in the other thread, http://modthesims.info/t/553279 , it is perfectly OK for an MLOD to have the same geostates in more than one mesh group.
If the geostate in one mesh group has face count = 0 and vertex count = 0, then none of the faces in that mesh group show up when that geostate is active.

So for a simple example with two geostates (and a default state which is never visible outside TSRW)
One group uses the whole [0] mesh for geostate A, and geostate B has face count = 0 and vertex count = 0
The other group uses the whole [2] mesh for geostate B, and geostate A has face count = 0 and vertex count = 0

Hope this helps

Peter


@peter9g This detailed instructions is very useful. But I'm stuck at Step 5. Where do you get the hash naming conventions from? Are you choosing them at random or are they derived from anywhere? I'm referring to the instructions you are giving in this thread: http://modthesims.info/t/553279
Test Subject
#20 Old 1st Aug 2016 at 3:25 AM
Quote:
Originally Posted by olomaya
This detailed instructions is very useful. But I'm stuck at Step 5. Where do you get the hash naming conventions from? Are you choosing them at random or are they derived from anywhere? I'm referring to the instructions you are giving in this thread: http://modthesims.info/t/553279


Hi Olomaya

The geostate name is an FNV32 hash.

Taking a bookcase as an examaple, we have geostates
HalfFull = 0x8A6C4E39
Base = 0x4CF9B596
and the code to change geostates will refer to the geostate by name
e.g.

public void SetGeoStates()
{
if (Objects.IsValid(base.ObjectId))
{
base.SetGeometryState("Base");
this.BookshelfGeoState = VisualState.Base;
}
}


Hope this helps

Peter
MakeNeedsStaticOn
staff: moderator
Original Poster
#21 Old 1st Aug 2016 at 7:49 PM Last edited by Greenplumbbob : 1st Aug 2016 at 9:21 PM.
So basically it's the like gnomes changing poses. That was the exact information I needed to make things clearer for me ^-^ Thank you so much!

EDIT: @Peter9g Small question, Is it necessary to add a new group to the bonfire? I know that the bookcases has 3 meshes, although the thing with the university bonfire, it only has 2 meshes in the mlod located. When adding a new mesh to it ( [2] mesh), it will think there are two meshes of the same mesh (Usually there is only the shadow map and the mesh of the bonfire. Now I have duplicated bonfires, which I think leaves me skipping step 1).

Second question. When you say 'assign it to the groups assign each to its own group in Milkshape' does that mean I need to call everything to it's own Geostate? Or do I need to merge them together in some way with the correct vertex count and other information in S3PE?

EDIT: @Olomaya, To generate the FV32hash, Open S3PE, Right+click 'add' (or Resource>add). In the name bar, write down Base (without any ""). You'll get a generated Instance. just copy the part till the numbers stop and you only have 0.

For example:

The script says that "Base" is the name of the geostate.(In this exact part of the script in fact):

base.SetGeometryState("Base");
this.BookshelfGeoState = VisualState.Base;

Base is a name. When generating 'Base' with S3PE's FV32Hash tool, you see that Peter9g generated the correct name for it. '4CF9B596' Just add the 0x to it and you'll be fine. For the other geostate, just add 'HalfFull' to S3PE's FV32Hash tool, you'll get also the same numbers that were given by Peter9g ^-^
Forum Resident
#22 Old 2nd Aug 2016 at 4:50 AM
Thank you @peter9g and @Greenplumbbob! Very helpful

I'm sure I'll be back with more questions.
MakeNeedsStaticOn
staff: moderator
Original Poster
#23 Old 2nd Aug 2016 at 1:05 PM
I'm having issues with my Blender ts3 tool now *sigh*. Everything that the plugin should have in it's tab is there, the only thing that's empty is the geostate editor. I tried going all the way around with Milkshape, but that doesn't seem to be working at all.



Unless I missed something to actually activate it?
MakeNeedsStaticOn
staff: moderator
Original Poster
#24 Old 2nd Aug 2016 at 6:55 PM
Sorry for the amount of posts >-<

I'm wondering. It's a bit like the Dollhouse problem here. One dollhouse is all fine, the other is broken.
The bonfire I have, has 3 states. If I would add them together in one group, it's a bit hard to select them/add the correct values. (Or even selecting everything in TSRW). So in my case, what would be the best way to add the geostates for the bonfire? Or, make the game see there are 3 different 'states'. (If this was a backpack, it would have been easier though >-<)

(In case if you're wondering what I meant with the 3 states: http://modthesims.info/showthread.p...741#post5060741
Test Subject
#25 Old 2nd Aug 2016 at 9:36 PM
Quote:
Originally Posted by Greenplumbbob
Sorry for the amount of posts >-<

I'm wondering. It's a bit like the Dollhouse problem here. One dollhouse is all fine, the other is broken.
The bonfire I have, has 3 states. If I would add them together in one group, it's a bit hard to select them/add the correct values. (Or even selecting everything in TSRW). So in my case, what would be the best way to add the geostates for the bonfire? Or, make the game see there are 3 different 'states'. (If this was a backpack, it would have been easier though >-<)

(In case if you're wondering what I meant with the 3 states: http://modthesims.info/showthread.p...741#post5060741


It still might be possible to use one mesh entry (TSRW Group 0) if the Blender exporter writes out the individual states one after the other.
The geostates for the bonfire that you show in TSRW clearly don't match the states in Blender, but one thing that you haven't shown in the TSRW screenshots is what happens if you expand the geostate listing to show the complete
FaceCount
IndexBufferOffset
VertexBufferOffset
VertexCount
listing

I suspect that the Geostates all have IndexBufferOffset = VertexBufferOffset = 0, whereas what you really want is to increase the offsets for each successive geostate so that you only read the parts of the VBUF and IBUF that correspond to a single state.
i.e.
increase the VertexBufferOffset for Geostate N+1 by the VertexCount of Geostate N, and
increase the IndexBufferOffset for Geostate N+1 by 3*FaceCount for Geostate N.

Make sure in this scenario that the VertexCount and FaceCount for Geostate 0 are less than the counts for the whole Group 0 mesh.

Hope this helps

Peter
Page 1 of 2
Back to top