Work was begun today on my most complex and ambitious oopasm class to date.
The BSP Class provides all the functionality required for the Indoors Engine of a real game. I expect to use a separate terrain engine for outdoors scenes similar to the Fusion Engine.
It's a full-blown BSP Loader and Renderer which makes full use of the BSP Tree for Visual Surface Determination, LightMapping, HintBrushes, the whole lot. Oh yeah, it's for DirectX :)
I just wanted to let you guys know what I've been up to. I'll post something more concrete just as soon as I feel I have made some decent progress.
Have a nice day :)
Posted on 2003-12-27 03:06:55 by Homer
Homer,

I look forward to see your oopasm class :grin:
Posted on 2003-12-27 04:11:17 by roticv
Good :) It's huge, the translation work is not difficult, there's just a lot of it, I'll be looking for some help to ease to workload.
Very early days, here's the BSP Class barely began translation, obviously initially concentrating on the Loader, theres some smaller dependant classes that will need translating too, and one or two we can do without..
Posted on 2003-12-27 07:41:00 by Homer
Well I already made a mistake, I should be using OVERLAPPED File Access so I ca set the FilePointer to the appropriate offset since the Loader does not use sequential file access to read the data :( I will fix that before I go any further :(
I don't think it's clever to just load the whole file and then parse it. I'll do it the right way :(
Posted on 2003-12-27 08:26:55 by Homer
Following a suggestion by Ultrano, I changed away from using OVERLAPPED file access to use FileMapping instead. Progress was made in the Loader to the point where we can load the Vertex, Index, Surfaces and LightMaps, and enumerate the Texture FileNames but I stopped short of loading the Textures themself, or performing gamma correction on the LightMaps. I need to now stop and write the CTexture Class before I continue. At any rate, the current code is working to that point, and has been tested as such. Any progress is good progress :)
Posted on 2003-12-27 14:28:29 by Homer
More progress was made - in fact, the Loader is virtually complete.
All the procedures called by BSP_LOAD have been translated, with the minor exceptions outlined in the previous post.
After loading the test.bsp which Zabnik provided in his OpenGL-based BSP offering, my Debug LogFile contains the following:

Found 24 Vertices
Found 36 Indices
Found 6 Surfaces
Found 1 Textures
textures/gothic_floor/q1metal7_97
Found 1 LightMaps
Found 18 Nodes
Found 16 Leaves
Found 6 LeafSurface Indices
Found 18 LeafBrush Indices
Found 24 Planes
Found 0 Clusters
Found 6 Brushes
Found 36 BrushesSides
BSP File Maps\test.bsp Read OK

I now need to write the dependant classes CPlane, CBoundingBox, CPrimitive and CTexture, the last one I've almost completed, the others barely started, especially CPrimitive because its big - really, REALLY big ...
w00t !!

Zabnik if you read this post, please confirm the accuracy of my results since my Loader is nothing like yours, I'm actually walking the Lump Directory.
Posted on 2003-12-27 23:42:08 by Homer
it was level.bsp not test.bsp you probaly mistmatched?

eh :( if i could upload my new version which loads lightmap
Posted on 2003-12-28 10:54:32 by zabnik
The 53kb file test.bsp was in your first upload, zabnik.. I may have renamed it but don't recall doing so.. anyways, did you sort out your issues with gamma? The source I posted contains gamma correction code but I haven't translated it yet because I'm still trying to decide how best to handle a particular issue in the CTexture class...
Posted on 2003-12-28 16:32:58 by Homer
Heya :)
I think I've finally decided how to deal with the issue I was having with the CTexture Class.
The problem involved an ambiguous part of the c++ standard template library called "Map". It was used to keep a LinkedList of sorts which prevented us from loading a named texture more than once, but didn't stop us creating multiple class object instances that refer to the same texture.
The solution I have decided on is to use an external procedure to create instances of Ctexture, and keep the object pointers in a LinkedList which is referenced by name. Not only does this prevent us from reloading a loaded texture, but it prevents us from creating multiple instances of a class object that refer to the same loaded texture. w00t :D
In order to achieve this I've decided to use my OLD LINKEDLIST SUPPORT MODULE which Scronty helped me with very early in 2003.

Here is the proposed code, with no comments sorry.
I haven't even tested it out yet.
Attached is the LinkedList support module itself.


.data
TextureCacheRoot dd NULL ;ptr to the ROOT ENTRY of a LinkedList of TextureInfo structs
.code
include LinkedList.inc ;<--- This is the LinkedList Support Module I coded ages ago
CachedTexture struct
LO LinkedObject <> ;LinkedList header supports naming and linking
pCTexture dd NULL ;Pointer to instance of CTexture Class Object
Count dd NULL
CachedTexture ends


;The following code is used to keep a LinkedList of "CachedTexture" structs
;which in turn is used to ensure we only create ONE INSTANCE
;of a CTexture Class Object for a given Texture FileName.
;We CAN try to load a named Texture more than once,
;but it will only return a reference to an already existing instance.
;The return value is always a ptr to a CTexture object instance,
;and NOT an actual DX texture ptr, thats kept inside the class object.

NewTexture proc pName:DWORD, multipleLevel:DWORD, colorKey:DWORD
local pCachedTexture:DWORD
local pCTexture:DWORD
.if TextureCacheRoot
invoke FindEntryByName, TextureCacheRoot, pName
.if eax==NULL
mov pCachedTexture, $invoke (AddChildEntry, TextureCacheRoot,sizeof CachedTexture)
invoke NewName, pCachedTexture, pName
mov pCTexture, new CTexture
icall pCTexture, CTexture, Load, pName, multipleLevel, colorKey
mov ebx,pCachedTexture
m2m .CachedTexture.pCTexture, pCTexture
inc .CachedTexture.Count
return pCTexture
.else
inc .CachedTexture.Count
return .CachedTexture.pCTexture
.endif
.endif
mov pCachedTexture, $invoke (AddChildEntry, NULL ,sizeof CachedTexture)
mov TextureCacheRoot,eax
invoke NewName, pCachedTexture, pName
mov pCTexture, new CTexture
icall pCTexture, CTexture, Load, pName, multipleLevel, colorKey
mov ebx,pCachedTexture
m2m .CachedTexture.pCTexture, pCTexture
inc .CachedTexture.Count
return pCTexture
NewTexture endp
Posted on 2003-12-28 18:54:16 by Homer
What all that boils down to is this:
we end up with ONE instance of a class object per loaded texture.
Therefore the Class itself can assume an instance of the object is unique, and does not need to perform any internal checking for this.
Similarly, the reference count for a given texture is kept outside the Class, in the LinkedList structure, and therefore the Class doesn't need to worry about that either. Finally, it means we NEVER EVER create instances of CTexture ourself, we call our NewTexture procedure, which will either return a new class object instance, or an existing one. (Polite applause.)
Posted on 2003-12-28 19:11:50 by Homer
Here's the "mostly complete" CTexture class :)
Oh look, it's beer o'clock already :grin:
Priorities are : cold beer, then CBoundingBox, then CPrimitive.
After that I can finish up the BSP Loader and start on the Render code.
w00t :alright:
Posted on 2003-12-28 20:28:45 by Homer
The above method for managing the CTexture class object instances was implemented, and the base methods of CTexture were implemented.
BSP_ReadTextures was completed, and BSP_ReadLightMaps was completed, and is generating lightmaps based on the given Gamma factor.
w00t :grin:
Posted on 2003-12-29 05:19:55 by Homer
Well, converting C++ source at once and then compile didnt helpt me, when i tried to render simple vertex so im doing everything by BSP file specs, and almost no c++ source, I think you got more asm programming xp than I, and I think your Loader will be more successfull than my, Good Look!:alright:
Oh, and thanks for Gamma-Value-Correction snippet it works fine, my tiny version:


mov esi,pImageBits
mov ecx,128*128*3
.while ecx
xor eax,eax
mov al,byte ptr [esi]
[b]imul eax, r_gamma
.if eax > 255
mov byte ptr [esi], 255
.else
mov byte ptr [esi], al
.endif[/b]
add esi,1
dec ecx
.endw
Posted on 2003-12-29 07:45:22 by zabnik
Thanks for the feedback, happy to be of assistance in some small way :)
Theres nothing wrong with loading the way you did, it's just not as nice.
Whatever works I usually say, however I'm trying to keep this translation true to the c++ on which it is based before I go screwing with it.
I have many years experience as a machinecoder and lowlevel programmer, but I have only about 3 years on the x86. I still learn something every day or two.
It's not the Loader I'm concerned about as much as the render code, but keeping it modular should help me debug down the track should that become necessary. Also, I'm comfortable with modular code for a few other reasons. OOP in asm is something relatively new to me in terms of this kind of class based implementation, however I can see the benefits from a mile away, especially when it comes to things like inheritance and overloading. I hope to get the Loader half completed in the next few days but obviously tomorrow is out because I'm going to be so rolling drunk that I don't know which way my up vector is pointing :D
Posted on 2003-12-29 09:39:38 by Homer
Work continues with CBoundingBox class which is about 50% completed.
I'll try to avoid CPrimitive altogether.
That means when CBoundingBox is completed, the Loader can be completed, and it will be time to start on the Render side of the code.
w00t :grin:
Posted on 2003-12-30 07:57:54 by Homer
Great! But where did u get the C++ source I want to look at it and learn something

I got a strange thing here, im doing PVS, and when i render LEAFS it draws only 31 faces my map has 38 faces but when I add
BoxInFrustum,.BSP_LEAF.min_x,.BSP_LEAF.min_y,.BSP_LEAF.min_z,.BSP_LEAF.max_x,.BSP_LEAF.max_y,.BSP_LEAF.max_z
I see one part of map which I dont see without it, hmm soo strange.
And for future:


if(!m_clusters.pBitsets || current < 0) return 1;
// Use binary math to get the 8 bit visibility set for the current cluster
byte visSet = m_clusters.pBitsets[(current*m_clusters.bytesPerCluster) + (test / 8)];
// Now that we have our vector (bitset), do some bit shifting to find if
// the "test" cluster is visible from the "current" cluster, according to the bitset.
int result = [b]visSet & (1 << ((test) & 7));[/b]
// Return the result ( either 1 (visible) or 0 (not visible) )
return ( result );

Im stuck at this one, especialy at "visSet & (1 << ((test) & 7))", can u help, C++ tries to make me confused, for its easyer to know how the BSP works than converting C source, but these BSP-tree specs are English, not my Language that I speak.
Posted on 2003-12-30 08:07:16 by zabnik
visSet & (1 << ((test) & 7))

=



mov eax, _test
and eax, 7
xor ecx, ecx
bts ecx, eax
and visSet, ecx
Posted on 2003-12-30 08:16:29 by roticv
You can find the c++ source on which I am basing this work here :)
Posted on 2003-12-30 11:39:30 by Homer
Here is 80% translated CBoundingBox class.
Be safe and see you all next year :)
Posted on 2003-12-30 22:36:56 by Homer
Day One of 2004.
The first dependant function in CBoundingBox was implemented, and thus BSP_ReadNodes was completed. All tested and working. BoundingBoxes for Nodes are being calculated. Therefore I am posting the BSP class source and its dependant classes source as they stand.

Have a nice day :)
Posted on 2004-01-01 04:17:14 by Homer