Jump to content
COMBATSIM Forum
Krycztij

TAW terrain format

Recommended Posts

Great stuff!

Been a bit too busy today to look into the LOD stuff :angry: , but will try and find time this evening.

...it requires "damage" and "parameter" both to be set to make damage visible:

Note that the 0048 opcode selects which parameter is active for the comparisons which follow.

For damage, which is parameter 7, we get this sequence:

00480007

...then some comparision rules. zero is always the undamaged state.

The only other one I know for sure what it does is parameter 000a, which selects for the 4 F22 camo schemes.

Share this post


Link to post
Share on other sites

:icon_bow:

Wow, there is something really neat we should try to do:

The aswaan high dam seems to not have any damage model and no way to destroy it.

Other dams have the nice little feature of breaking, and then water floods the valley.

Any way we could achieve the same for the aswaan high dam?

Share this post


Link to post
Share on other sites

Having trouble with the LODs, but found out some things:

1. There is always at least one LOD, ie the second word of the .3 file is always non-zero.

2. The maximum number of LODs is four.

3. What we call type '0020' and '00a3' only ever have one LOD.

4. For type '0000', the start of the bytecode for each LOD can be found by the following logic:

        if self.type=='0000' or self.type=='0020':

            code_start=int(data[17],16)/2+18

            if self.lod2dist!=0:

                code_start2=int(data[18],16)/2+19

            if self.lod3dist!=0:

                code_start3=int(data[19],16)/2+20 

            if self.lod4dist!=0:

                code_start4=int(data[20],16)/2+21             

That leaves types '0083' and '0087'. While quite a few of them follow similar rules to the '0000' type using the value of the 18th,19th and 20th words, I haven't been able to find a general rule. :(

Share this post


Link to post
Share on other sites

Sorry for the bad news, DrKevDog, but: Yes, your hardware is too old. My Notebook has 945 Chipset, not 845. From what I see, the 845 came out in 2001/2002 and does not support DirectX 9 pixel shaders.

Krycztij,

I appreciate your efforts. In a few days I will be able to move this project off the backup system and it should work fine, until then I will continue working on the file discussion topics. In the meantime, thanks for the screenshots, they are helpful.

And this is Dave:

daver.png

Thanks for finding 'Dave', I found that head a few years ago while file searching (which I don't believe is used in TAW), and then I simply lost my head :rolleyes:

Personally, I don't believe that is Dave. I suspect that file was erroneously named by assumption. There is no Dave.3 in the standard TAW 3 folder and there are no SSD calls to that file name. The ssinfo.fn index does not list a 'Dave' 3file-name. There is a dave.ssd and it has association with and is probably a substitution for (reason yet to be determined) the terrain tile Khartoum_f.ssd. Just an FYI ;)

Share this post


Link to post
Share on other sites

:icon_bow:

Wow, there is something really neat we should try to do:

The aswaan high dam seems to not have any damage model and no way to destroy it.

Other dams have the nice little feature of breaking, and then water floods the valley.

Any way we could achieve the same for the aswaan high dam?

Not to mention the "lip" that juts out uses a texture rather than a color from the palette. In TAW 2.0, the corresponding texture has some green, which gives it a "moldy" look. If we could isolate the line, I would like to substitute the existing texture with another that is a neutral sand texture.

Share this post


Link to post
Share on other sites

Again great to see the work going on here. If we can maintain our current improvement in the number of MP fliers, TAWBC mission planners and your work here; TAW2.0 is shown to be live and healthy. By the by, the Dam shot is so familiar to many of us who fly MP. It forms part of one of out favorite missions. :thumbsup:

Yes, TAW is great game and I'm very glad there is still such a lively community.

Note that the 0048 opcode selects which parameter is active for the comparisons which follow.

For damage, which is parameter 7, we get this sequence:

00480007

...then some comparision rules. zero is always the undamaged state.

The only other one I know for sure what it does is parameter 000a, which selects for the 4 F22 camo schemes.

Oh noe the more I implement the more complicated it becomes! :D I have now twice as many opcodes as yesterday; most of them are just skipped. Almost all models are loading now. But because it's just the 0th LOD, the screen is often blank.

Having trouble with the LODs, but found out some things:

1. There is always at least one LOD, ie the second word of the .3 file is always non-zero.

2. The maximum number of LODs is four.

3. What we call type '0020' and '00a3' only ever have one LOD.

4. For type '0000', the start of the bytecode for each LOD can be found by the following logic:

        if self.type=='0000' or self.type=='0020':

            code_start=int(data[17],16)/2+18

            if self.lod2dist!=0:

                code_start2=int(data[18],16)/2+19

            if self.lod3dist!=0:

                code_start3=int(data[19],16)/2+20 

            if self.lod4dist!=0:

                code_start4=int(data[20],16)/2+21             

That leaves types '0083' and '0087'. While quite a few of them follow similar rules to the '0000' type using the value of the 18th,19th and 20th words, I haven't been able to find a general rule. :(

I suspected 1. 2. is valuable because now I roughly know how much data I must expect and I can identify when a LOD number is wrong. 3 is VERY valuable because it means many terrain tiles and simple models are now running with all their bytecode and not just the tip at the beginning of the file.

I'll implement 4. immediately. It is a great start. However: The real eye candy is 00870083 (it's all the planes). Even if you don't find a perfect pattern: Can you find a way to determine whether your byte #17/18/19/... trick from the other day works with a model or not? We would then have LOD with at least SOME of the 0083 models.

It's a pity TAW uses such complicated mechanisms for LOD. Many models use a "if distance above X then jump" opcode for their LOD and it works fine. w_delimo.3 is an example which works pretty good with my current internal build.

Also: If I manage to implement dummies of the complete instruction set this night, you'll get an update.

:icon_bow:

Wow, there is something really neat we should try to do:

The aswaan high dam seems to not have any damage model and no way to destroy it.

Other dams have the nice little feature of breaking, and then water floods the valley.

Any way we could achieve the same for the aswaan high dam?

Not to mention the "lip" that juts out uses a texture rather than a color from the palette. In TAW 2.0, the corresponding texture has some green, which gives it a "moldy" look. If we could isolate the line, I would like to substitute the existing texture with another that is a neutral sand texture.

Well, Aswaan does have a damage model, but it is very little. Before:

asok.jpg

and after:

asdmgd.jpg

(The white lines on top are lights. I forgot to switch them off before takjng the shots. Sorry.)Just noticed this is the wrong dam. Already wondered why it looks so small :( You are right, Aswan High Dam has no damage model. Sorry!

If we implement a flood, there is still very very much work to do. We are just scratching at the surface. There are about 50 parameter completely unknown to us. We need to decode the way the engine says what model is drawn and how she does it. But we're learning more and more each day.

Personally, I don't believe that is Dave. I suspect that file was erroneously named by assumption. There is no Dave.3 in the standard TAW 3 folder and there are no SSD calls to that file name. The ssinfo.fn index does not list a 'Dave' 3file-name. There is a dave.ssd and it has association with and is probably a substitution for (reason yet to be determined) the terrain tile Khartoum_f.ssd. Just an FYI ;)

Oh. I didn't extract DID.DAT myself because I could not find the tools any more. A kind community member sent me the extracted files I now work with four years ago. It was indeed named dave.3 there.

Share this post


Link to post
Share on other sites

Progress! The F-22 models are some of the hardest to render, so this is a big leap forward:

f22n.jpg

It is amazing to see how many details DiD put into the game:

detailz.jpg

There is, however, bad news, too: I have encountered BACKWARD jumps for the first time in the F-22 player models. I had, however, mistakenly assumed that there were only FORWARD jumps. This seemed plausible to me because it would prevent deadlocks and hangs by design. But now my jump verification mechanism is broken and needs to be rewritten :(

Share this post


Link to post
Share on other sites

There is, however, bad news, too: I have encountered BACKWARD jumps for the first time in the F-22 player models. I had, however, mistakenly assumed that there were only FORWARD jumps. This seemed plausible to me because it would prevent deadlocks and hangs by design. But now my jump verification mechanism is broken and needs to be rewritten :(

The backward jumps that I am aware of only occur with the AGP opcodes, specifically 00a3 which is basically works to determine if AGP flag is set then jump...

Ex:

00A3FF7E

0047003A000400000000004000000040004000000040

00880004000400090005000A

0000

00620004FE55FE550000

006B03560009

006C03560005

006BFCAA000A

00750004

00750009

00750005

0075000A

00A3FF2A

0047003A000400000000004000000040004000000040

00880004000400090005000A

0000

00620004FE32FE320000

006B039C0009

006C039C0005

006BFC64000A

00750004

00750009

00750005

0075000A

00A3FED6

IIRC it was a F22 pylon model. In what file(s) did you encounter the backward jumps? I take it from your switches you are intending to activate AGP in the viewer?

Share this post


Link to post
Share on other sites

In what file(s) did you encounter the backward jumps? I take it from your switches you are intending to activate AGP in the viewer?

No, the AGP flag is always false here. (Though it could be a bug; I implemented about 10 new flags and a typo which mistakes the AGP flag with something else would not be unlikely.) I encountered it in f22usa1.3:

3109; 002000019e26    ; If Parameter 0005 < 1 then jump to line 8

This is the instruction where I actually crashed. It was a bad surprise indeed; I have tested more than 500 models since this morning and none ever had a backwards jump. F-22 was one of last models not to load. Now only pylon models remain (I was too lazy to implement bytecode search vor 0087; but I'm on it now).

Share this post


Link to post
Share on other sites

No, the AGP flag is always false here. (Though it could be a bug; I implemented about 10 new flags and a typo which mistakes the AGP flag with something else would not be unlikely.) I encountered it in f22usa1.3:

3109; 002000019e26    ; If Parameter 0005 < 1 then jump to line 8

This is the instruction where I actually crashed. It was a bad surprise indeed; I have tested more than 500 models since this morning and none ever had a backwards jump. F-22 was one of last models not to load. Now only pylon models remain (I was too lazy to implement bytecode search vor 0087; but I'm on it now).

It's not a typo. Not sure what parameter 5 is here but going back to 0087 may provide answers.

Share this post


Link to post
Share on other sites

I'll check that later. Priorities ;) There are also huge problems with the visibility test in the same file, and textures won't load correctly either. And there are still about 20 opcodes not implemented (which means crashes on files that use them).

Mike, here is a patch to most recent build, with LODs for 0000 and 0020 files. 95 % of all .3 files load (meaning: "are executed without a crash"; not "looking correct"). Copy the old version in case the new one does not work as expected. Keys are pretty much the same; mouse wheel can be used for zoom (distance relative to model radius written on the top-left) and arrow up / down for LOD selection. Would be great if you confirmed that it runs.

http://www.mediafire.com/?4nfztoq39ro3x6x

Btw: Is there no possibility to attach files here? I feel a little stupid for uploading 27 K to mediafire and my mail provider does not permit sending ZIP with EXE :)

My plan is to hack in the remaining opcodes, maybe implement mouse rotation and release tomorrow. After the initial release, it should be easy to see which instructions have priority and it should be easier for us to decode the unknown instructions, synce we have an impression of how the rendered data looks then.

Share this post


Link to post
Share on other sites

Oh yes, it runs fine :thumbsup:

It even shows up the problem at aswan_q which has long irked Home Fries.

I'm going to be late for work if I don't stop trying 'just one more' model. :)

Will continue the LOD investigation later.....

Share this post


Link to post
Share on other sites

Glad to hear that.

I'm going to be late for work if I don't stop trying 'just one more' model. :)

I know that feeling so well!

104 Opcodes are now implemented; I think that's all of them. (You listed 99, maybe there were some old false positives in your script which are now in mine, too.) 42 are fully implemented.

I'll now do some minor improvements on stability and, if I have some spare time, test the not-well-known opcodes. I'll release the first public version then.

Also: antenna.3 indicates that 0000-type models store their LODs in most-detailed-first order.

Share this post


Link to post
Share on other sites

104 Opcodes are now implemented; I think that's all of them. (You listed 99, maybe there were some old false positives in your script which are now in mine, too.) 42 are fully implemented.

Looks like I didn't keep the list updated. With hindsight, we could probably rationalise things a bit.

What I haven't done is work out exactly which opcodes are used for 'subroutine' calls and thus must terminate with a '0000' in order for the program to flow correctly. I guess you're working this out the hard way.

Also: antenna.3 indicates that 0000-type models store their LODs in most-detailed-first order.

Ah yes, and it's the other way round for 0083/0087.

Share this post


Link to post
Share on other sites

What I haven't done is work out exactly which opcodes are used for 'subroutine' calls and thus must terminate with a '0000' in order for the program to flow correctly. I guess you're working this out the hard way.

No, I'm not working it out at all :) I'm just treating everything but 0008 as jumps. Works fine for many models; at least I'm not missing very much. There are still so many instructions to implement (known ones like the 009F you explained, too), so that trial-and-error is not the most efficient thing for me to do know :)

Looks like I didn't keep the list updated. With hindsight, we could probably rationalise things a bit.

I'm currently compiling the final ZIP and I'll publich it in a few hours. I was planning to freeze and re-evaluate the todo list anyway (so you can test around a little bit and say what has highest priority), it will include an enumeration of all opcodes. So, we'll see later.

Share this post


Link to post
Share on other sites

Just fixed a bug with Gouraud-shaded vertices having wrong colors before releasing :)

First: I'll take a few days off, getting the viewer to run was quite stressy over the last weeks ;)

It's a good chance to have a quick revue on what we have so far. Here is a list of all instructions known to the viewer:


Fully implemented:


0000 Return

0001 DrawFlatShadedLine

0002 DrawFlatShadedTriangle

0003 DrawFlatShadedQuad

0008 Call

0015 JumpIfTriangleIsInvisible

0020 JumpIfParameterIsBelow

0021 JumpIfParameterEquals

0022 JumpIfParameterIsAbove

0027 JumpIfDistanceAbove

002E FetchPolygonUV

002F DrawTexturedPolygon

0030 Scale

0033 DrawSignalLight

0034 DrawLight

0039 DrawStreetLights

0047 FetchPolygonUV

004C FetchTriangleColors

004E FetchQuadColors

0062 WriteXYZ

0063 WriteNextXYZWithXYZDelta

0064 WriteNextXYZWithXDelta

0065 WriteNextXYZWithYDelta

0066 WriteNextXYZWithZDelta

0067 WriteNextXYZWithXYDelta

0068 WriteNextXYZWithXZDelta

0069 WriteNextXYZWithYZDelta

006A WriteRandomXYZWithXYZDelta

006B WriteRandomXYZWithXDelta

006C WriteRandomXYZWithYDelta

006D WriteRandomXYZWithZDelta

006E WriteRandomXYZWithXYDelta

006F WriteRandomXYZWithXZDelta

0070 WriteRandomXYZWithYZDelta

0071 DrawNextFlatShadedTriangle

0072 DrawNextFlatShadedQuad

0080 DrawGouraudShadedTriangle

0081 DrawGouraudShadedQuad

0088 DrawTexturedPolygon

008E DrawTexturedPolygon

00A3 JumpIfAGPAvailable

FFFF EndOfLoD



Partly implemented:


0007

0024

0025

0026

002D

003F JumpIfLightsOn

0040

0043 JumpIfTimeOfDayEquals

0049

004B

0061 CompleteXYZFetching

0076

007B

007C

0087

0093

0095 DrawLight

0098 TransparencyLevel

009F



Just being skipped:


0004

0006

001A

001B

001F

002C

0031

0036

0037

0038

003E

0041

0042

0045

0048

004A

004D

004F

0050

0051

0052

0053

0054

005C

005D

005F

0060

0073

0075

0077

007D

007E

007F

0083

0084

0086

008D

0094

0096

009D

009E

00A2

00A7

00A8

Immediately on my todo list is implementing Gouraud shading for the 009F instruction (it is just skipped currently) and implementing the 0071 (repeat previous) instruction.

The next non-bytecode thing I'd like to do is implement color palettes and time of day. This will, however, take at least one week. (I need to test the whole INI parser, remove the currently hard-coded references, etc.)

Then, alpha blending and AGP textures would be a nice thing. From what I know, TAW just applies transparency to some color palette entries; that should be done rather quick.

And we should have a look at the f22cl***.3 files; something goes terribly wrong with vertex positions there. But it could also be due to the viewer ignoring 0071.

Generally speaking, I think we should look into models which load almost perfectly but have one or two unknown instructions with easy-to-spot glitches in them. Since the unknown effects are pretty much isolated in there, we should have a good chance to understand what's going on. Then we proceed with the next almost perfect model etc. In my opinion, w_delimo.3 is a good example for translation instructions (the tires!). And if we decode it, all mobile ground targets and many planes will profit.

What do you think?

Share this post


Link to post
Share on other sites

No, I'm not working it out at all :) I'm just treating everything but 0008 as jumps.

:superscare:

What do you think?

I think you've done a brilliant job!

Regarding the 'unknown' opcodes, we have our theories ranging from fairly sure about what they do, to not having a clue. :)

Share this post


Link to post
Share on other sites

Regarding aswan_q, the 'tongue' is defined by trg_4.tm, but as this is completely transparent, you see what is underneath.

I've changed trg_4 to the next index up, which happens to be 'plane_19.tm'

aswan1.jpg

Not the desired final result, but shows what can be done in 5 minutes with the help of this tool. :thumbsup:

Share this post


Link to post
Share on other sites

Generally speaking, I think we should look into models which load almost perfectly but have one or two unknown instructions with easy-to-spot glitches in them. Since the unknown effects are pretty much isolated in there, we should have a good chance to understand what's going on. Then we proceed with the next almost perfect model etc. In my opinion, w_delimo.3 is a good example for translation instructions (the tires!). And if we decode it, all mobile ground targets and many planes will profit.

Sounds like a plan :thumbsup:

What do you think?

Congratulations, very nice work!

Share this post


Link to post
Share on other sites

Thank you all.

I had a quick look into transparency (0088 opcode). The palette entries are re-interpreted:


0-31: color is black, opacity is color index / 31

32-63: color is white, opacity is (color index - 32) / 31

This works well on ships and ground units (oliver and sa17):

olivery.png

sa17.png

It's okay on clouds:

cloudsr.png

But it's way too faint on fzaim9x:

sidewinder.png

Anyone has more information on how transparency works and which models use it?

Share this post


Link to post
Share on other sites

The only thing I can add right now is that the 0098 opcode adjusts the transparency, eg this line from fzaim9x:

0254; 0098fffe ; Transparency level -2

..I'm not sure whether this is supposed make the transparency more or less opaque though.

Building shadows like those in tent_3 show this up quite well, where the opacity of the shadow depends on the distance to the building.

Share this post


Link to post
Share on other sites

The only thing I can add right now is that the 0098 opcode adjusts the transparency, eg this line from fzaim9x:

0254; 0098fffe ; Transparency level -2

..I'm not sure whether this is supposed make the transparency more or less opaque though.

Building shadows like those in tent_3 show this up quite well, where the opacity of the shadow depends on the distance to the building.

Those are only used for vertex transparency; they have no influence on transparent textures. It was an error in my renderer: I forgot to apply gamma correction to my premultiplied alpha. It works well now, even for fzaim9x.

I'm currently implementing the 009F opcode according to your explanation:

I noticed the program hangs on the 009f opcode. This is used quite a lot and needs a bit of explanation.

Here's an example from tent_3.3

0039; 009f000e0070040100b700b700bc00bc009e0000000100070006 ; Quad

0040; 009f000c0072030100b800ba00b7009d000500000006 ; Triangle

Taking the quad, and splitting it up:

009f 000e 0070 0401 00b7 00b7 00bc 00bc 009e 0000 0001 0007 0006

This can either render a gouroud shaded polygon or a textured polygon depending on an 'Options' menu setting.

In both cases, the 4 words at the end give the vertex indices.

For the shaded polygon, 00b7 00b7 00bc 00bc give the palette colours for each vertex.

The textured polygon is more complicated. The 0070 is an index to the [surface] section of a 'redXXXX.ini' file.

Here's part of the one from red1000.ini:


[surface]

0=txtr 4,(0,0),(31,0),(31,31),(0,31)			;N	CONCRETE

1=txtr 4,(32,0),(63,0),(63,31),(32,31)			;NE	CONCRETE

2=txtr 4,(64,0),(95,0),(95,31),(64,31)			;E	CONCRETE

3=txtr 4,(96,0),(127,0),(127,31),(96,31)		;SE	CONCRETE

..

107=txtr 5,(224,128),(255,128),(255,159),(224,159)    	;NW	ROCK DEAD

108=txtr 55,(192,128),(223,128),(223,159),(192,159)    	;BOT	ROCK DEAD

109=txtr 55,(224,128),(255,128),(255,159),(224,159)    	;TOP	ROCK DEAD

110=txtr 5,(0,160),(31,160),(31,191),(0,191)		;N	CANVAS DEAD

111=txtr 5,(32,160),(63,160),(63,191),(32,191)		;NE	CANVAS DEAD

112=txtr 5,(64,160),(95,160),(95,191),(64,191)		;E	CANVAS DEAD

113=txtr 5,(96,160),(127,160),(127,191),(96,191)	;SE	CANVAS DEAD

..

119=txtr 55,(224,160),(255,160),(255,191),(224,191)    	;TOP	CANVAS DEAD

So 0070 is hex for 112, so we need this line: 112=txtr 5,(64,160),(95,160),(95,191),(64,191) ;E CANVAS DEAD where 'txtr_5' is itself a pointer to the actual texture given in the first part of red1000.ini: 5=mattdead ....so, 'mattdead.tm' is the texture to use with UV coordinates given by the figures in the brackets, in this case: (64,160),(95,160),(95,191),(64,191) There are a couple of variations of this opcode with flat shading, where only one colour is defined. This part of my script which determines the lengths of the various variants:

            elif opcode=='009f':

                gen1=data[ind+3]

                gen3=data[ind+5]

                gen4=data[ind+7]

                gen2=""

                mm=0

                if gen1=='0401':

                    while mm<13:

                        gen2+=data[ind+mm]

                        mm+=1

                    self.parsed.append(gen2)

                    pind+=1

                    ind+=13

                elif gen1=='0301' and gen4<>'009e':

                    while mm<11:

                        gen2+=data[ind+mm]

                        mm+=1

                    self.parsed.append(gen2)

                    pind+=1

                    ind+=11

                elif gen1=='0301' and gen4=='009e':

                    while mm<13:

                        gen2+=data[ind+mm]

                        mm+=1

                    self.parsed.append(gen2)

                    pind+=1

                    ind+=13

                elif gen1=='0900':

                    while mm<18:

                        gen2+=data[ind+mm]

                        mm+=1

                    self.parsed.append(gen2)

                    pind+=1

                    ind+=18                    

                elif gen1=='0103' and gen3=='009d':

                    while mm<9:

                        gen2+=data[ind+mm]

                        mm+=1

                    self.parsed.append(gen2)

                    pind+=1

                    ind+=9                    

                elif gen1=='0103' and gen3=='009e':

                    while mm<10:

                        gen2+=data[ind+mm]

                        mm+=1

                    self.parsed.append(gen2)

                    pind+=1

                    ind+=10

I could only load the 0301 and 0401 versions yet, but:

From my understanding, if the first opcode word is 000e, then the third opcode word is 0401, four colors follow, then 009e, finally four position indices.

If the first word is, on the other hand, 000c, then the third opcode word is 0301, three colors follow, then 009d, finally three position indices.

Your code, however, expects 009e even when the first word was 000c. Can you provide any file where this actually happens? I tried some of the bigger files (factories, warehouses, tents) by chance, but I couldn't find one.

Furthermore: I doubt 009F is one instruction. I rather think it is two: 009F to fetch color and texture information and 009D/009E to draw the actual triangle/quad (much like 002E and 002F, which appear in pairs, too). There is a high degree of redundancy in 009F (if I am correct with the 000E/0401/009E thing above, we have three words to determine whether it renders a triangle or a quad) which is not found in any other instruction, and if it were actually two seperate instructions, this would be an explanation.

Edit: I see: Your parser actually expects 009D and 009E instructions with opcode+3 and opcode+4 words, respectively. I am now very sure 009F is actually split; 009D means "draw textured or shaded triangle depending on settings" and 009E means "draw textured or shaded quad depending on settings".

Share this post


Link to post
Share on other sites

I did a scan for 000c associated with 009e and got 3 hits:

ammobild.3

amobl90.3

amobl_90.3

and this example is from ammobild.3:

0194; 009f000e0000040100c400c400c300c3009e0005000400110012    ;

0195; 009f000c0009030100c600c600c6009e000a0003000400050000    ; <-------------------

0196; 009f000c0003030100c600c300c3009d0008001a0018    ;

..probably some anomoly.

I agree that 009f should be split up. I did the code for 009f before coming across 'free standing' 009d and 009e.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...