MS3D Texture Array.

Started by
8 comments, last by whyisitalwaysme2 15 years, 6 months ago
I recently took up the task of making my ms3d loader compatible with vertex arrays. Which has been successfuly so far. I made a parser application which modified the triangle structure so that all the vertex indices were right next to each other. i could then point to the first vertex indice specified in the mesh struct specify how many to draw from the meshs triangle count variable and draw the mesh. My draw loop merely jumps to the next mesh and then its around 10 lines of ASSEMBLY code to setup the draw, nice eh? Kinda like this: Indice1,Normal1,Tex1,Indice2,Normal2,Tex2 becomes -> Indice1 Indice2 Tex1 Tex2 Normal1 Normal2 Now onto my problem, When i come to the texture coordinates. The s and t coordinate are separated in m_s[3] and m_t[3] in the triangle structure. so i need to interleave them right? so what i need is this: m_s[1],m_t[1],m_s[2],m_t[2],m_s[3],m_t[3] and i did just that. But unfortunatly it doesnt work. When the textures display theyre all distorted and skewed. This tells me that they are wrong. But before i spend several hours trying to port my assembly code into C :D. Am i doing it right? am i meant to do m_s[1],m_t[1],m_s[2],m_t[2],m_s[3],m_t[3]? In a bit of a rush atm, i can post some much more informative code later on.
Advertisement
Quote:Original post by whyisitalwaysme2
My draw loop merely jumps to the next mesh and then its around 10 lines of ASSEMBLY code to setup the draw, nice eh?
Why in all the hells are you writing an OpenGL application in assembly? I could possibly understand it if you were coding one of those 4k demos, but in that case you wouldn't be using a format as inefficient as milkshape.
Quote:But before i spend several hours trying to port my assembly code into C :D
And why you would then port that assembly code to C is an absolute mystery...

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

It's about speed/efficiency and control, if your doing something yourself as a hobby, you may as well do it properly. Assembly fair enough, can't actually be used for anything in the *real world* but once you start and see just how much lighter and less bloated it is, programming in c (low level by todays standards) irritates you :p.

As for milkshake, like i said, im building a parser which cuts out all useless information and then reorders it all for use with vertex arrays.etc And yes, its a crap file format. I was going to make an importer and exporter but its all written in c++ and i have to import lib files, so i figured it would be quicker just to parse an ms3d file.

And by porting to c i meant just the bits of code relevant to my problem, so that more people on here could actually make sense of it.
I just tried something else. When i call glDrawElements, and it looks through the indices does it select texture coordinates out from the array like it does with the vertex coords? in other words do the the indices also index which texture coords to draw as well as which vertex coordinates?

Im really confused. My hex editor is showing a nice clean parse of the data being placed in the right places in my output file :/.

Heres my assembly code for parsing, havent ported it yet. its unoptimized since im constantly redoing it over and over in different ways. Assume Source points to the start of the original files triangle structures.

          mov      dword[Counter],0          TransferTriangleTex:                   mov      eax,dword[Counter]                   mov      ecx,70                   mul      ecx                   add      eax,44                   mov      ebx,eax                   add      ebx,dword[SourceFilePointer]                   add      ebx,dword[SourceFileBuffer]                   mov      eax,dword[DestinationFileBuffer]                   add      eax,dword[DestinationFilePointer]  ;eax= dest, ebx= src                   mov      ecx,dword[ebx]      ;s                   mov      dword[eax],ecx                   mov      ecx,dword[ebx+12]                   mov      dword[eax+4],ecx     ;t                   mov      ecx,dword[ebx+4]     ;s                   mov      dword[eax+8],ecx                   mov      ecx,dword[ebx+16]     ;t                   mov      dword[eax+12],ecx                   mov      ecx,dword[ebx+8]     ;s                   mov      dword[eax+16],ecx                   mov      ecx,dword[ebx+20]     ;t                   mov      dword[eax+20],ecx                   add      dword[DestinationFilePointer],24          inc      dword[Counter]          mov      eax,dword[Count]          cmp      dword[Counter],eax          jne      TransferTriangleTex       
Quote:Original post by whyisitalwaysme2
It's about speed/efficiency and control, if your doing something yourself as a hobby, you may as well do it properly.
That assumes that you have sufficient knowledge of instruction scheduling, caching, memory latencies, etc. to optimise better than the compiler. Your code is SIMD optimised, right?
Quote:Assembly fair enough, can't actually be used for anything in the *real world* but once you start and see just how much lighter and less bloated it is, programming in c (low level by todays standards) irritates you :p.
Methinks you missed the entire point of programming languages, if you regard C as bloated in this day and age...
Quote:As for milkshake, like i said, im building a parser which cuts out all useless information and then reorders it all for use with vertex arrays.etc And yes, its a crap file format. I was going to make an importer and exporter but its all written in c++ and i have to import lib files, so i figured it would be quicker just to parse an ms3d file.
This is even less a job for assembly. Write a converter in a high-level language (such as python, or ruby), that outputs a slimmed-down binary format you can load with your assembly. Even if you insist on writing your application in assembly for (very dubious) performance reasons, simple tools don't need that level of performance, so you should be writing them in an easy language.
Quote:And by porting to c i meant just the bits of code relevant to my problem, so that more people on here could actually make sense of it.
A fair number of us can read ASM - it is a requirement for most CS degrees, after all.
Quote:I just tried something else. When i call glDrawElements, and it looks through the indices does it select texture coordinates out from the array like it does with the vertex coords? in other words do the the indices also index which texture coords to draw as well as which vertex coordinates?
All vertex elements use the very same index - i.e each value in the index array specifies the same offset into each of the vertex, normal and texture-coord arrays.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Okay thats ruled something out at least.

Although a lot of people can read asm its not exactly a mainstream language, im not trying to sound elitist or anything, its just i want this solved :/. I do try to follow basic optimization procedures such as caching and byte alignment for memory, i am aware of how complex and intelligent compilers are these days.

SIMD? not so much, Couple of areas where my code could benefit from some SSE/MMX with maybe parallel processing but not enough to make me actually stop and get the intel docs out and spend several hours on a small piece of code for 10-20 cycles. Obviously wherever theres code that does a repeated job on a large amount of data ill be more inclined to go for SIMD optimized first time :p. But this is things like a couple of trig operations for basic movement. This May contradict my previous statement of taking my time or even using assembly at all but i like to get a *section* of a program done before i go back and clean it up.


I could of definetly used python/ruby and hell, i should have. But i had actually written half the code in assembly before i even realised it. You see my code is derived from Nehe's lesson 31 where the guy does all the parsing at load time. I was porting this and realised i should probably run this process on the file at development time instead of runtime. So it was a bit of a copy and paste job but your right, assembly is stupid for this.



Okay in my draw loop i set my vertice pointer to the start of my vertices for all meshes, and since all my triangle structures have been altered to be in chunks. All my normals and texture pointers point to the start of a large array for all meshes.

Here i after i load the file i set the pointers

;Find Verticesmov       eax,[ModelBuffer]movzx     ecx,word[eax]mov       [VerticeCount],ecxadd       eax,2mov       [VerticePointer],eax;Find Trianglesmov       eax,13mul       [VerticeCount]add       eax,[VerticePointer]movzx     ebx,word[eax]mov       [TriangleCount],ebxadd       eax,2mov       [TrianglePointer],eax;Find Meshesmov       eax,66mul       [TriangleCount]add       eax,[TrianglePointer]movzx     ecx,word[eax]mov       [MeshCount],ecxadd       eax,2mov       [MeshPointer],eax;Find Normalsmov       eax,6mul       [TriangleCount]add       eax,[TrianglePointer]mov       [NormalPointer],eax;find Texture Coordsmov       eax,36mul       [TriangleCount]add       eax,[NormalPointer]mov       [TexturePointer],eax  


proc   ModelRenderinvoke glVertexPointer,3,GL_FLOAT,0,[VerticePointer]invoke glNormalPointer,GL_FLOAT,0,[NormalPointer]invoke glTexCoordPointer,2,GL_FLOAT,0,[TexturePointer]mov    eax,[MeshPointer]mov    [CurrentMeshPointer],eaxmov    [MeshCounter],0DrawMesh:       cmp    [MeshCounter],0       je     SkipMeshJump       mov    eax,[MeshTriangleCount]       mov    ebx,2       mul    ebx       add    eax,3       add    [CurrentMeshPointer],eax       SkipMeshJump:       mov    ebx,[CurrentMeshPointer]       movzx  eax,word[ebx+3]       mov    ecx,6       mul    ecx       mov    ecx,eax       add    ecx,[TrianglePointer]       movzx  eax,word[ebx+1]       mov    [MeshTriangleCount],eax       mov    ebx,3       mul    ebx       invoke glDrawElements,GL_TRIANGLES,eax,GL_UNSIGNED_SHORT,ecxinc    [MeshCounter]mov    eax,[MeshCount]cmp    [MeshCounter],eaxjne    DrawMeshretendp                    


And Here is my parse loop which is unchanged from yesterday which converts the data file which the above code reads.

          mov      dword[Counter],0          TransferTriangleTex:                   mov      eax,dword[Counter]                   mov      ecx,70                   mul      ecx                   add      eax,44                   mov      ebx,eax                   add      ebx,dword[SourceFilePointer]                   add      ebx,dword[SourceFileBuffer]                   mov      eax,dword[DestinationFileBuffer]                   add      eax,dword[DestinationFilePointer]  ;eax= dest, ebx= src                   mov      ecx,dword[ebx]      ;s                   mov      dword[eax],ecx                   mov      ecx,dword[ebx+12]                   mov      dword[eax+4],ecx     ;t                   mov      ecx,dword[ebx+4]     ;s                   mov      dword[eax+8],ecx                   mov      ecx,dword[ebx+16]     ;t                   mov      dword[eax+12],ecx                   mov      ecx,dword[ebx+8]     ;s                   mov      dword[eax+16],ecx                   mov      ecx,dword[ebx+20]     ;t                   mov      dword[eax+20],ecx                   add      dword[DestinationFilePointer],24          inc      dword[Counter]          mov      eax,dword[Count]          cmp      dword[Counter],eax          jne      TransferTriangleTex    


Ive kind of narrowed it down to 2 thing. Either theres a tiny barely noticeable mistake *somewhere* or im not actually interleaving the coordinates correctly.
Sorry for the crappy code :/.
Quote:Original post by whyisitalwaysme2
SIMD? not so much, Couple of areas where my code could benefit from some SSE/MMX with maybe parallel processing but not enough to make me actually stop and get the intel docs out and spend several hours on a small piece of code for 10-20 cycles.
My point is that modern compilers offer automatic SIMD optimisation, as well as all that pesky register allocation and cache optimisation...

Quote:Ive kind of narrowed it down to 2 thing. Either theres a tiny barely noticeable mistake *somewhere* or im not actually interleaving the coordinates correctly.
Despite my earlier statement, I am finding your assembly pretty hard to follow [smile]
However, it does appear that you are interleaving your texture coordinates correctly, so I would guess a bug somewhere.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Quote:
The t values are all set to 1.0-(original value). The reason for this is that OpenGL uses a lower-left coordinate system, whereas Milkshape uses an upper-left coordinate system for it's texture coordinates. This reverses the y coordinate.


Just went through the nehe tut and noticed that by sheer chance. God dammit. i HATE this file format XD.
okay i made a model with a single triangle. Here is the actual data stored from [TexturePointer] when its non interleaved (note i havent inverted the t coords yet):

What i have currently:

Uninterleaved
S = 3F 00 00 00/00 00 00 00/00 00 00 80
T = 3F 00 00 00/00 00 00 80/3F 00 00 80

Interleaved:

s1 t1 s2 t2 s3 t3
3F 00 00 00/3F 00 00 00/00 00 00 00/00 00 00 80/00 00 00 80/3F 00 00 80

Okay so what i need to know is, which is the negative flag? 80 or 3F?

Once i know this i can calculate the T coords values...make up a triangle in immediate mode with manually calculated coords and see exactly how to arrange them.

So close!

This topic is closed to new replies.

Advertisement