I agree. Objective-C does have some nice features.
But, still, some of the most powerful tools in Lisp are things like the closure of having data and code use the same representation and the wonderful things that lets you do, such as the Lisp defmacro system.
CLOS with is dynamic multiple-dispatch (read generics) with user-definable method-combinations.
I'll repeat defmacro again because it's the real reason that Lisp lets you do really really good bottom-up programming as well as the standard top-down approach, instead of the pure top-down approach that obj-c and c++ make you use. I mean, good luck writing one of those (with-... (code)) macros in Obj-C.
User-defined methods being indistinguishable from regular keywords is also part of making bottom-up programming possible and more powerful.
True dynamic typing of ALL types, not this obj-c 'id' thing where only class pointers are dynamically typed.
You mentioned scheme. So, what about call/cc (call-with-current-continuation) which lets you "unroll" and take parts of code and rip them "inside-out" to make them easier to use and understand.
What about the fact that an incredibly powerful OO system like CLOS can be built on top of Lisp, at run-time, using nothing but Lisp code.
I don't think Obj-C or any other language of that style will ever come close to the pure flexibility of Lisp.
I'll grant you that Obj-C has some nice features. But the "best" of Lisp I still have to take issue with.
Dual processor G4. Can ship with 2GB of DDR. You can get them with Ultra160 SCSI. They ship with DVD-RAM, DVD, CD-RW, CD. They have Gigabit, 100Mb and 10Mb ethernet. Also optional 802.11b (11Mb).
So, dual proc, SCSI, DVD-RAM, fast pipe.
And yet, it's still a home machine. Well, an expensive home machine. But still technically a home machine.
Before a card can be marked as OpenGL 1.3 complient it must be able to run the full OpenGL 1.3 test suite perfectly.
This test suite includes the core OpenGL api and all of the required extensions ARB_, NV_ and otherwise.
If it can't pass them, it isn't complient.
The engine I have will run on any OpenGL 1.3 complient video card correctly.
I have tested it on TNT2, GeForce2, GeForce3, ATI Radeon 7500, ATI Radeon Mobile.
And on the following OS's:
Linux, FreeBSD, OpenBSD, Solaris 8, Mac OS X, Win2k, WinXP.
So, not nearly as thoroughly as Quake 3 has been tested, but not bad for a home developer.
Yes, I could probably optimize it more by writing portions of it for each video card separately. Or, I could hand-code chunks of it is assembler for each supported processor.
But, I figure, that's the point of standards. I am standards complient. If the video card is too, it will run correctly.
Dude. Carmack uses OpenGL. He had to do some hacks for speed because he didn't have OpenGL 1.3 or 1.4. There are some new, satndard extensions in them that make things faster that he didn't have. I do, so I used them.
Most complex games are written in either OpenGL or Direct3D. What, do you think everyone writes there own software renderer?
If you care, I've written a simple textured poly software renderer as well as a simple (no reflections/refractions) ray tracer.
No game HAS done good physics before. Not because they can't. Because they didn't need to. Game companies aren't willing to devote hte time and effort into physics because they don't need it to make money. Physics isn't that important in the final experience.
I AM devoting the time to it. And should have it working well in a year. I say this because i've implemented most of it before in smaller chunks.
I've implemented OBB and ABB trees and done collisions with them. I've done poly/poly collisions.
I've implemented simple rigid body dynamics. Keep track of angular and linear momentum. Accumulate forces. Determine torque and displace components. Take into account intertia tensor.
It's not that bad. It's just that most people don't want to do it.
Oh, that reminds me. A friend and I are working on a 3D engine.
We just started not that long ago. No real algorithms yet. We aren't satisfied with BSP+PVS. We are doing for octrees w/ occlusion culling. Which isn't implemented yet.
All we have right now is simple Quadtree based terrain. But we have a good framework to build on. And we are abstracted away from the underlying API's relatively well. Still a lot more work to do there.
But, it's up and running. Works on OS X, Win32, FreeBSD, OpenBSD, Solaris and Linux.
It's under the MIT license and will be made public as soon as we have a bit more functionality and the GL 2.0 renderer up and running.
Yes, it does support all video cards. All video cards that support OpenGL 1.3. Which abstracts away the problem of supported video cards.
Networking, Physics and Model support are more complicated problems. There is no standard way of implementing Physics and Models. There are many competing ideas for models. Some prefer skeletal animation. Some do keyframe stuff without skeletons. Either way, this stuff is relatively difficult and there is no standard "one way" to do it.
Physics has never been done well in a game. The most I've ever seen is BASIC rigid body dynamics with connection points between various hulls. Full rigid body dynamics takes more time, but, I am working on it. I hope to have a GOOD physics and collision detection implementation is about a year.
BSP+PVS w/ Q3 maps and shaders do have one well-known way to do it. And it's easy. And it can be done in a week.
I DO know what I'm talking about. I AM developing a 3D engine.
In fact, you agreedf with me. I said you could develop a 3d engine support BSP+PVS and Q3 maps and shaders in a week. You then agreed with me.
Then you said, "but you couldn't do it with features X and Y that you never said you could do it with and therefore you were wrong."
This makes no sense.
The details are, like I said, what make the Q3 engine a good purchase. It's mature and has lots of features. But it's graphics technology is old and can be hacked together in a week.
BSP trees work by breaking up the world into arbitrary convex hulls. This is good because you can render a convex hull that you are inside without worry about some of the triangles overlapping other ones.
In other words, take two cubes connected by a recangular hallway.
Theoretically the BSP tree could divide this into three sectors. One for each room, and one for the hallway. Each of these individual sectors is a convex hull.
So, if you are in the sector for a room you can just render that entire sector, without using a z-buffer or any kind of depth testing, and you don't have to worry about things overlapping. I mean, there is nowhere in a room where you can stand where the left wall and the floor will overlap.
See what I mean?
Now, while you are rendering the room you render it's portals. It has a portal connecting it to the hallway sector. So, you render the hallway's sector, clipped to the polygon that is the portal.
Then, while drawing the hallway you draw the sector connecting to the second room. So, you draw the second room, clipped to the portal leading from the hallway to that room, which is already clipped to the original portal.
So, we just drew the two rooms and the hallway, with no traingles overlapping.
This is exactly how the original portal-based renderers worked.
Now, why doesn't this work for outdoor scenes?
Imagine a large field with rolling hills. Now, try and find a convex hull. It's tough.
Imagine a hill shaped like a dome.
This dome forms a conCAVE hull. You can't break it down in to ANY convex hulls. So, every single triangle has to be part of it's own, unique, convex hull.
So, now every triangle in this hill is it's own sector. Our BSP tree is huge. And we have MILLIONS of portals connecting every triangle to the ones next to it.
This is HORRIBLY ineffient and slower than just brute force rendering.
So, to summarize. Indoor scenes tend to be easily decomposable into convex hulls. And hence work well with BSP trees and PVS. Outdoor scenes aren't. They tent to have a lot of concave areas.
Q3 technology is NOT top-notch. It WAS, for a game engine. But no more.
It's poly-counts are very low for today's game's standards. BSP+PVS, with indoor geometry only, is a bit antiquated. It supports no REAL lighting/shadowing model. There's no support for pixel and vertex shaders. The AI is almost non-existant. The network code and latency are mediocre by today's standards.
The Q3 engine is OLD. So is the tech behind it.
Now, it is mature, and it does expose a relatively usable API for mod developers and such.
But, just to implement all the Q3 tech, including BSP+PVS, Q3 Shaders and a loader for the Model files and Map files would take two good 3D engine programmers about a week.
Binary space partitioning trees proper have fallen out of use in games.
All BSP-based games now-a-days use Solid Leaf BSP trees, which are a variation of the original and have many more useful properties for games.
It is these trees and the sectors that they create that are used for determining portals.
If two sectors have the same portal then those two portals connect and can see eachother. If a portal has no pair, then it is a portal out in to infinite space and is hence a leak in your map. Assuming, of course, a map based on a single BSP tree.
Once you have portals, PVS generation is easy. And there you go, BSP and PVS.
A lot of modern research is shying away from BSP and PVS. They limit you to indoor spaces. Entirely different technology is required for outdoor scenes. And then special hacks and logic are needed to allow for seamless transitions between the indoor and outdoor worlds.
Some think that octrees with a form of occlusion culling might very well be better as they can represent both indoor and outdoor geometry without making any distinction between them. They are much harder to cull though as no handy PVS information is present and only more difficult methods exist such as Z-pyramids.
Others stick with BSP and PVS and use the one-sided portals that would normally represent leaks but instead in this case represent windows from the BSP into the terrain, and vice-versa. This combined with some extra lighting and shodow-volume information and you can have your lighting and transitioning between indoor and outdoor be seemless.
I am unaware of the formal definition of RTTI, so you may very well be correct.
If by RTTI you mean the ability to manually determine the type of a pointer via typeid and the ability to do dynamic_cast then, yes, obviously C++ would support RTTI.
What I was referring to would be more accurately described by two terms. First off, dynamic vs static typing. C++ is obviously static. There aren't that many problems with this, but there are many useful things that can only be easily done with dynamic typing. Secondly, as my example demonstrated, single vs multiple dispatch. Where C++ chose single and CLOS uses multiple-dynamic.
Anyway, yeah, this is probably another terminology thing. Being completely self taught there are a fair number of industry standard terms whos concepts I am familiar with but names I am not. This is one of those cases.
Like you, I only know around a dozen of the 30 languages I've used in any depth. Some of those dozen are functional, others procedural.
My comments about RTTI in C++ are NOT wrong, however. C++ does not have run-time type checking of arguments to functions. It has inheritance, and with it virtual functions. This means that if you have a class and a subclass, and instances of each, that even if you cast the subclass to be a pointer to the superclass, if you try and call one of it's methods it will still call the one of the subclass, assuming it's virtual.
In other words:
class Super { public:
void foo() { printf("Super::foo()"); } };
class Sub : public Super { public:
void foo() { printf("Sub::foo()"); } };
int main(int argc, char** argv) {
Super* s1 = new Super();
Super* s2 = new Sub();
s1->foo();
s2->foo();
delete s1;
delete s2; }
This code will produce the following: Super::foo() Sub::foo()
So, theres polymorphism. Now, what about RTTI of arguments to functions. Known as multiple-dispatch. Unfortunately, C++ only implements single-dispatch, which means choosing the appropriate method based on the type of the object via which the method is being called. So:
class Super { public:
void foo() { printf("Super::foo()"); } };
class Sub : public Super { public:
void foo() { printf("Sub::foo()"); } };
I think OO is a fabulous concept, but I am more in favor of higher level languages. I think LISP's CLOS has the best object model I've used. Classes with slots. Accessors. Generics w/ multiple dispatch.
I find C++ limiting due to its lack lf runtime type checking, which disallows some of the more elegant solutions to problems and gives rise to the need for such hacks as the Visitor "pattern."
As Paul Graham, the LISP guru, so elegantly put it (this is NOT verbatim):
"I don't like patterns. When I see patterns in my code it means I'm not working at a high enough level of abstraction."
I disagree that I've fallen into this "faddish trap." I've used C, C++, Assembler, Prolog, Scheme, LISP, Ada, SML/NJ, OCaml, Fortran, Cobol, Pascal, BASIC, Java, Perl, Python, Ruby, Eiffel, Erlang, Forth and far more languages that I can't pull off the top of my head.
Language has nothing to do with style. Some languages just take care of more of the work for you and abstract you more from the underlying machine.
You CAN write "OO-style" code, meaning code that exhibits features such as polymorphism, data-hiding, encapsulation and such in absolutely any language. You can do XP style programming in any language.
But you can't do OO unless you have Objects, which you can't do unless you have a language that has objects, unless you make them yourself, in which case you've changed the "core" language.
Then again, this is probably just semantics. I can't find the right way to express this belief.
I am more than familiar with the different styles of programming. From structured programming to OO, from procedural to functional to concurrent, from static scoping to dynamic scoping, from compile-time to run-time binding, from eager to lazy evaluation. I may be green, but I am a fast learner.
I think I actually agree with everything you say, and I think you'd agree with most of what I say, surprisingly. It's just my lack of communication skills today that may be letting us down.
Yes, OO has been around that long. Almost 30 years now. But as I'm only 21 that doesn't do me much good.:-).
I am not confusing language and structure. If anything it is, again, a problem of terminology. Perhaps my definitions, as you point out, are not mainstream. They made perfect sense to me and seem to follow from the composition of the term "object-oriented" but it is possible that they are not mainstream.
You are correct that the benefit comes from the style, not the language. The bookkeeping, however, is not of lesser value. It is necessary (more or less). It's just a question of whether you implement it yourself or whether the compiler and language do it for you.
While OO is probably not a "fad" in the way you refer to it, in another sense it is. OO has become such a buzzword itself that many people get lost and assume that OO IS programming. That procedural programming is somehow antiquated and OO is the way of the future.
I suppose that's possible. But if it's true then I'm ashamed to be a programmer. I've used over 30 languages in my short time as a programmer and am very familiar with the concepts involved. OO, atleast in almost all current implementations, in severely limited. Even more so in Java where it's a damned shame that they diluted the term OO by using Java as an example.
Anyway, I see your point about my terminology and I apologize for the confusion. I hope you can see the point I was trying to make about the separation of built-in functionality and home-grown functionality, of language and style.
The future, in my mind, is with a separation of data from algorithms. Data exist in the forms of classes with a mostly common interface. They provide no functionality, only server to wrap up data. Algorithms exist as generics (Generic Methods, called via Multiple Dispatch).
This gives you all of the benefits of OO with none of the problems.
OO is a valiant attempt to allow for polymorphism, but in my mind one that is doomed to fail. It will likely be replaced slowly and evolutionarily as programmers hate paradigm changes because they invalidate all that they have learned.
I call the buzzwords because they predated and will eventually post-date the fad of OO programming and yet are always used in relation to OO. I full know well what they mean. I've been doing OO programming for almost 10 years.
No, you can not write OO in assembler. To do so would require doing all of the bookkeeping by hand with regular variables. In which case you have implemented an OO framework on top of assembler. In which case you are actually programming in the meta-language you implemented on top of assembler.
I realize i'm being pedantic here, but it's a matter of terminology. OO code is code that uses objects, whether or not those objects are themselves messes of spaghetti code. OO style is a method of writing objects that take advantage of the OO buzzword list.
OO style can be written in any language, including assembler, C, Pascal, you name it.
OO code however can only be written in an OO language.
If you implement an OO framework on top of assembler then you are actually programming in your framework, which is an OO meta-language.
You CAN'T write a structured procedural program in a Pure-OO language like java without having those procedures be class methods.
Since all of your procedures are now class methods, your program is in a object, and hence, object-oriented.
You CAN NOT write a NON-OO program in a PURE-OO language. It CAN NOT BE DONE.
It may not be the style of OO that you are used to. In fact it may very well be a dirty hack of reimplementing a procedural program in an OO language with the least amount of code change possible.
It may be all public and disobey every rule of good OO design you've ever learned.
But, if it's composed of nothing but classes with methods, then it's Object Oriented. This is just a fundamental definition of the term Object Oriented as meaning comprised of Objects where objects are instances of classes. And in C++, yes, classes are very similar to namespaces, which are just buckets for methods and variables, but, guess what, that's all classes are too.
Again, it's a terminology problem. It's the difference between an OO program and a program written in a OO style. You MUST write an OO program when using a pure OO language. But you need not use OO style. You can write OO programs in a non-OO style. You cannot write non-OO programs in a pure OO language.
A program that "contains objects", and is composed entirely of said "objects" CAN be considered OO, no matter what.
Style has nothing to do with classification.
Whether you use data-hiding, inheritance, encapsulation, polymorphism, [insert OO buzz-word here], is up to you.
It's still OO if your language is Pure-OO. That's what the name Pure-OO means for god's sake.
Yes, it might not be good OO-style. It may not be XP. But, good OO-style and XP are both fads. They have only been around for a few years and probably won't be around in the same form in a few more.
You can't say something isn't transportation because it doesn't get you to your destination the way you want to get there. It's transportation as long as it gets you there.
But, I do understand your point about Pure-OO languages not necessarily leading to GOOD OO programs. And I agree whole-heartedly. No language can make you a good programmer.
Why ew? Because of your limited programming experience with languages where this was eschewed?
In general, in computers, closure is a good thing. Ask any functional programmer. Ask any language theorist. Closure is good. To simplify closure, I am referring to having rules that don't have exceptions. Having a uniform representation for as much as possible.
In LISP data and code are stored the same way, as lists. This is the ultimate closure. Other languages implement other closures like having all data types be of a common type.
> What you really need is generics (as in C++ templates).
Lord God NO! Don't you EVER use C++ templates as an example of generics again. C++ templates are an attrocity. What you want is generic methods with multiple-dispatch. Look at Lisp's CLOS, or Dylan.
> However, that wouldn't make all Java programs "object-oriented programs",
Explain? How can you write a Non-OO program in a Pure-OO language? Cause, you see, it's not possible. You can write a program that isn't in the OO style that you think of when you think of OO. But you can't write a program that has data that isn't an "object" in a Pure-OO language.
> I have a suspicion that it might impact things like the JNI too
JNI would be as fine as it is now (yuch). Even the "float" class has to have an internal variable that actually stores the float.
I agree. Objective-C does have some nice features.
But, still, some of the most powerful tools in Lisp are things like the closure of having data and code use the same representation and the wonderful things that lets you do, such as the Lisp defmacro system.
CLOS with is dynamic multiple-dispatch (read generics) with user-definable method-combinations.
I'll repeat defmacro again because it's the real reason that Lisp lets you do really really good bottom-up programming as well as the standard top-down approach, instead of the pure top-down approach that obj-c and c++ make you use. I mean, good luck writing one of those (with-... (code)) macros in Obj-C.
User-defined methods being indistinguishable from regular keywords is also part of making bottom-up programming possible and more powerful.
True dynamic typing of ALL types, not this obj-c 'id' thing where only class pointers are dynamically typed.
You mentioned scheme. So, what about call/cc (call-with-current-continuation) which lets you "unroll" and take parts of code and rip them "inside-out" to make them easier to use and understand.
What about the fact that an incredibly powerful OO system like CLOS can be built on top of Lisp, at run-time, using nothing but Lisp code.
I don't think Obj-C or any other language of that style will ever come close to the pure flexibility of Lisp.
I'll grant you that Obj-C has some nice features. But the "best" of Lisp I still have to take issue with.
Justin Dubs
Interesting.
The G4 desktops.
Dual processor G4. Can ship with 2GB of DDR. You can get them with Ultra160 SCSI. They ship with DVD-RAM, DVD, CD-RW, CD. They have Gigabit, 100Mb and 10Mb ethernet. Also optional 802.11b (11Mb).
So, dual proc, SCSI, DVD-RAM, fast pipe.
And yet, it's still a home machine. Well, an expensive home machine. But still technically a home machine.
Justin Dubs
> but I see the best of C++, Smalltalk, Lisp, and Java in Objective-C.
Hahahaha. Best of Lisp. Hahah. That kills me.
I guess you've never actually used most of Lisp then, if you think Obj-C has all of Lisp's "best" stuff.
Justin Dubs
I don't understand what you are trying to say about hard polygonal edges?
Polygons, decomposed into triangles, were chosen for a reason. What do you suggest?
A gaussian blur pass over the image before it's put on the screen?
Good lord. Imagine the headaches we'd all have after staring at that for a few hours.
Justin Dubs
Before a card can be marked as OpenGL 1.3 complient it must be able to run the full OpenGL 1.3 test suite perfectly.
This test suite includes the core OpenGL api and all of the required extensions ARB_, NV_ and otherwise.
If it can't pass them, it isn't complient.
The engine I have will run on any OpenGL 1.3 complient video card correctly.
I have tested it on TNT2, GeForce2, GeForce3, ATI Radeon 7500, ATI Radeon Mobile.
And on the following OS's:
Linux, FreeBSD, OpenBSD, Solaris 8, Mac OS X, Win2k, WinXP.
So, not nearly as thoroughly as Quake 3 has been tested, but not bad for a home developer.
Yes, I could probably optimize it more by writing portions of it for each video card separately. Or, I could hand-code chunks of it is assembler for each supported processor.
But, I figure, that's the point of standards. I am standards complient. If the video card is too, it will run correctly.
Justin Dubs
Dude. Carmack uses OpenGL. He had to do some hacks for speed because he didn't have OpenGL 1.3 or 1.4. There are some new, satndard extensions in them that make things faster that he didn't have. I do, so I used them.
Most complex games are written in either OpenGL or Direct3D. What, do you think everyone writes there own software renderer?
If you care, I've written a simple textured poly software renderer as well as a simple (no reflections/refractions) ray tracer.
No game HAS done good physics before. Not because they can't. Because they didn't need to. Game companies aren't willing to devote hte time and effort into physics because they don't need it to make money. Physics isn't that important in the final experience.
I AM devoting the time to it. And should have it working well in a year. I say this because i've implemented most of it before in smaller chunks.
I've implemented OBB and ABB trees and done collisions with them. I've done poly/poly collisions.
I've implemented simple rigid body dynamics. Keep track of angular and linear momentum. Accumulate forces. Determine torque and displace components. Take into account intertia tensor.
It's not that bad. It's just that most people don't want to do it.
Justin Dubs
Yes, you are exactly right.
In fact, I'm doing a good deal of research right now into octrees.
Would you have any good links or books to suggest for occlusion culling algorithms?
Justin Dubs
Oh, that reminds me. A friend and I are working on a 3D engine.
We just started not that long ago. No real algorithms yet. We aren't satisfied with BSP+PVS. We are doing for octrees w/ occlusion culling. Which isn't implemented yet.
All we have right now is simple Quadtree based terrain. But we have a good framework to build on. And we are abstracted away from the underlying API's relatively well. Still a lot more work to do there.
But, it's up and running. Works on OS X, Win32, FreeBSD, OpenBSD, Solaris and Linux.
It's under the MIT license and will be made public as soon as we have a bit more functionality and the GL 2.0 renderer up and running.
Should be by Christmas.
Justin Dubs
Yes, it does support all video cards. All video cards that support OpenGL 1.3. Which abstracts away the problem of supported video cards.
Networking, Physics and Model support are more complicated problems. There is no standard way of implementing Physics and Models. There are many competing ideas for models. Some prefer skeletal animation. Some do keyframe stuff without skeletons. Either way, this stuff is relatively difficult and there is no standard "one way" to do it.
Physics has never been done well in a game. The most I've ever seen is BASIC rigid body dynamics with connection points between various hulls. Full rigid body dynamics takes more time, but, I am working on it. I hope to have a GOOD physics and collision detection implementation is about a year.
BSP+PVS w/ Q3 maps and shaders do have one well-known way to do it. And it's easy. And it can be done in a week.
Justin Dubs
I DO know what I'm talking about. I AM developing a 3D engine.
In fact, you agreedf with me. I said you could develop a 3d engine support BSP+PVS and Q3 maps and shaders in a week. You then agreed with me.
Then you said, "but you couldn't do it with features X and Y that you never said you could do it with and therefore you were wrong."
This makes no sense.
The details are, like I said, what make the Q3 engine a good purchase. It's mature and has lots of features. But it's graphics technology is old and can be hacked together in a week.
Justin Dubs
You'll note in my original post that I didn't say you could write a game engine in that time.
I said you could write a 3D engine with a lot of the features of quake 3, namely BSP+PVS, Shaders and quake Maps and Models in a week or two.
And this is still true.
You can put words in my mouth and then tell me they are wrong all you want.
Justin Dubs
I wasn't arguing over the same thing that you are responding too.
I agree, making a mature engine takes time. I agree, paying money for a stable core and codebase IS worth it.
No, I didn't mention implementing the networking, or sound, or mod system. In fact, I mentioned NOT implementing them.
But, like I said. The tech IS old. The graphics functionality can be written in a week. I did it in a weekend.
It's the rest of the codebase, and the maturity, that makes it worth buying.
Justin Dubs
Okay kid.
I implemented a basic BSP+PVS engine that supported Q3 maps and shaders in a weekend.
I did NOT implement Q3 models. Nor sound. Nor networking. Nor a stable API for mod developers.
But, a basic BSP+PVS engine that supports Q3 maps and shaders CAN and HAS been developed in a weekend. I've DONE it.
Two good engine coders, in a week, should be able to do the same. Plus add in Q3 models.
It still doesn't help them get a mature API for mod folks, but it is a working tech demos.
Justin Dubs
No problem. This is a common question.
Here's the thing.
BSP trees work by breaking up the world into arbitrary convex hulls. This is good because you can render a convex hull that you are inside without worry about some of the triangles overlapping other ones.
In other words, take two cubes connected by a recangular hallway.
Theoretically the BSP tree could divide this into three sectors. One for each room, and one for the hallway. Each of these individual sectors is a convex hull.
So, if you are in the sector for a room you can just render that entire sector, without using a z-buffer or any kind of depth testing, and you don't have to worry about things overlapping. I mean, there is nowhere in a room where you can stand where the left wall and the floor will overlap.
See what I mean?
Now, while you are rendering the room you render it's portals. It has a portal connecting it to the hallway sector. So, you render the hallway's sector, clipped to the polygon that is the portal.
Then, while drawing the hallway you draw the sector connecting to the second room. So, you draw the second room, clipped to the portal leading from the hallway to that room, which is already clipped to the original portal.
So, we just drew the two rooms and the hallway, with no traingles overlapping.
This is exactly how the original portal-based renderers worked.
Now, why doesn't this work for outdoor scenes?
Imagine a large field with rolling hills. Now, try and find a convex hull. It's tough.
Imagine a hill shaped like a dome.
This dome forms a conCAVE hull. You can't break it down in to ANY convex hulls. So, every single triangle has to be part of it's own, unique, convex hull.
So, now every triangle in this hill is it's own sector. Our BSP tree is huge. And we have MILLIONS of portals connecting every triangle to the ones next to it.
This is HORRIBLY ineffient and slower than just brute force rendering.
So, to summarize. Indoor scenes tend to be easily decomposable into convex hulls. And hence work well with BSP trees and PVS. Outdoor scenes aren't. They tent to have a lot of concave areas.
So, hope that helps.
Justin Dubs
Q3 technology is NOT top-notch. It WAS, for a game engine. But no more.
It's poly-counts are very low for today's game's standards. BSP+PVS, with indoor geometry only, is a bit antiquated. It supports no REAL lighting/shadowing model. There's no support for pixel and vertex shaders. The AI is almost non-existant. The network code and latency are mediocre by today's standards.
The Q3 engine is OLD. So is the tech behind it.
Now, it is mature, and it does expose a relatively usable API for mod developers and such.
But, just to implement all the Q3 tech, including BSP+PVS, Q3 Shaders and a loader for the Model files and Map files would take two good 3D engine programmers about a week.
Justin Dubs
Binary space partitioning trees proper have fallen out of use in games.
All BSP-based games now-a-days use Solid Leaf BSP trees, which are a variation of the original and have many more useful properties for games.
It is these trees and the sectors that they create that are used for determining portals.
If two sectors have the same portal then those two portals connect and can see eachother. If a portal has no pair, then it is a portal out in to infinite space and is hence a leak in your map. Assuming, of course, a map based on a single BSP tree.
Once you have portals, PVS generation is easy. And there you go, BSP and PVS.
A lot of modern research is shying away from BSP and PVS. They limit you to indoor spaces. Entirely different technology is required for outdoor scenes. And then special hacks and logic are needed to allow for seamless transitions between the indoor and outdoor worlds.
Some think that octrees with a form of occlusion culling might very well be better as they can represent both indoor and outdoor geometry without making any distinction between them. They are much harder to cull though as no handy PVS information is present and only more difficult methods exist such as Z-pyramids.
Others stick with BSP and PVS and use the one-sided portals that would normally represent leaks but instead in this case represent windows from the BSP into the terrain, and vice-versa. This combined with some extra lighting and shodow-volume information and you can have your lighting and transitioning between indoor and outdoor be seemless.
Anyway, just the ranting of a bored man at work.
Justin Dubs
Ah, right, I see what you mean.
I am unaware of the formal definition of RTTI, so you may very well be correct.
If by RTTI you mean the ability to manually determine the type of a pointer via typeid and the ability to do dynamic_cast then, yes, obviously C++ would support RTTI.
What I was referring to would be more accurately described by two terms. First off, dynamic vs static typing. C++ is obviously static. There aren't that many problems with this, but there are many useful things that can only be easily done with dynamic typing. Secondly, as my example demonstrated, single vs multiple dispatch. Where C++ chose single and CLOS uses multiple-dynamic.
Anyway, yeah, this is probably another terminology thing. Being completely self taught there are a fair number of industry standard terms whos concepts I am familiar with but names I am not. This is one of those cases.
Thanks for clearing that one up,
Justin Dubs
Fair enough.
Sub::foo()
Like you, I only know around a dozen of the 30 languages I've used in any depth. Some of those dozen are functional, others procedural.
My comments about RTTI in C++ are NOT wrong, however. C++ does not have run-time type checking of arguments to functions. It has inheritance, and with it virtual functions. This means that if you have a class and a subclass, and instances of each, that even if you cast the subclass to be a pointer to the superclass, if you try and call one of it's methods it will still call the one of the subclass, assuming it's virtual.
In other words:
class Super {
public:
void foo() { printf("Super::foo()"); }
};
class Sub : public Super {
public:
void foo() { printf("Sub::foo()"); }
};
int main(int argc, char** argv) {
Super* s1 = new Super();
Super* s2 = new Sub();
s1->foo();
s2->foo();
delete s1;
delete s2;
}
This code will produce the following:
Super::foo()
Sub::foo()
So, theres polymorphism. Now, what about RTTI of arguments to functions. Known as multiple-dispatch. Unfortunately, C++ only implements single-dispatch, which means choosing the appropriate method based on the type of the object via which the method is being called. So:
class Super {
public:
void foo() { printf("Super::foo()"); }
};
class Sub : public Super {
public:
void foo() { printf("Sub::foo()"); }
};
void Receiver(Super *super) {
printf("Receiver(Super)");
super->foo();
}
void Receiver(Sub *sub) {
printf("Receiver(Sub)");
sub->foo();
}
int main(int argc, char **argv) {
Super *s1 = new Super();
Super *s2 = new Sub();
Receiver(s1);
Receiver(s2);
delete s1;
delete s2;
}
This will produce the following output:
Receiver(Super)
Super::foo()
Receiver(Super)
See the problem? That's due to C++ single-dispatch nature.
Justin Dubs
Haha. No need to play it nice. :-)
I think OO is a fabulous concept, but I am more in favor of higher level languages. I think LISP's CLOS has the best object model I've used. Classes with slots. Accessors. Generics w/ multiple dispatch.
I find C++ limiting due to its lack lf runtime type checking, which disallows some of the more elegant solutions to problems and gives rise to the need for such hacks as the Visitor "pattern."
As Paul Graham, the LISP guru, so elegantly put it (this is NOT verbatim):
"I don't like patterns. When I see patterns in my code it means I'm not working at a high enough level of abstraction."
I disagree that I've fallen into this "faddish trap." I've used C, C++, Assembler, Prolog, Scheme, LISP, Ada, SML/NJ, OCaml, Fortran, Cobol, Pascal, BASIC, Java, Perl, Python, Ruby, Eiffel, Erlang, Forth and far more languages that I can't pull off the top of my head.
Language has nothing to do with style. Some languages just take care of more of the work for you and abstract you more from the underlying machine.
You CAN write "OO-style" code, meaning code that exhibits features such as polymorphism, data-hiding, encapsulation and such in absolutely any language. You can do XP style programming in any language.
But you can't do OO unless you have Objects, which you can't do unless you have a language that has objects, unless you make them yourself, in which case you've changed the "core" language.
Then again, this is probably just semantics. I can't find the right way to express this belief.
I am more than familiar with the different styles of programming. From structured programming to OO, from procedural to functional to concurrent, from static scoping to dynamic scoping, from compile-time to run-time binding, from eager to lazy evaluation. I may be green, but I am a fast learner.
I think I actually agree with everything you say, and I think you'd agree with most of what I say, surprisingly. It's just my lack of communication skills today that may be letting us down.
Regardless, thanks for the feedback.
Justin Dubs
1 trillion triangles!
To put things in perspective the GeForce 4 TI 4600 can do maybe 15 - 20 MILLION triangles per second.
So, PS3 will be as fast as 50,000 GeForce 4's running in parallel?
Justin Dubs
Yes, OO has been around that long. Almost 30 years now. But as I'm only 21 that doesn't do me much good. :-).
I am not confusing language and structure. If anything it is, again, a problem of terminology. Perhaps my definitions, as you point out, are not mainstream. They made perfect sense to me and seem to follow from the composition of the term "object-oriented" but it is possible that they are not mainstream.
You are correct that the benefit comes from the style, not the language. The bookkeeping, however, is not of lesser value. It is necessary (more or less). It's just a question of whether you implement it yourself or whether the compiler and language do it for you.
While OO is probably not a "fad" in the way you refer to it, in another sense it is. OO has become such a buzzword itself that many people get lost and assume that OO IS programming. That procedural programming is somehow antiquated and OO is the way of the future.
I suppose that's possible. But if it's true then I'm ashamed to be a programmer. I've used over 30 languages in my short time as a programmer and am very familiar with the concepts involved. OO, atleast in almost all current implementations, in severely limited. Even more so in Java where it's a damned shame that they diluted the term OO by using Java as an example.
Anyway, I see your point about my terminology and I apologize for the confusion. I hope you can see the point I was trying to make about the separation of built-in functionality and home-grown functionality, of language and style.
The future, in my mind, is with a separation of data from algorithms. Data exist in the forms of classes with a mostly common interface. They provide no functionality, only server to wrap up data. Algorithms exist as generics (Generic Methods, called via Multiple Dispatch).
This gives you all of the benefits of OO with none of the problems.
OO is a valiant attempt to allow for polymorphism, but in my mind one that is doomed to fail. It will likely be replaced slowly and evolutionarily as programmers hate paradigm changes because they invalidate all that they have learned.
Justin Dubs
I call the buzzwords because they predated and will eventually post-date the fad of OO programming and yet are always used in relation to OO. I full know well what they mean. I've been doing OO programming for almost 10 years.
No, you can not write OO in assembler. To do so would require doing all of the bookkeeping by hand with regular variables. In which case you have implemented an OO framework on top of assembler. In which case you are actually programming in the meta-language you implemented on top of assembler.
I realize i'm being pedantic here, but it's a matter of terminology. OO code is code that uses objects, whether or not those objects are themselves messes of spaghetti code. OO style is a method of writing objects that take advantage of the OO buzzword list.
OO style can be written in any language, including assembler, C, Pascal, you name it.
OO code however can only be written in an OO language.
If you implement an OO framework on top of assembler then you are actually programming in your framework, which is an OO meta-language.
Justin Dubs
I still disagree.
You CAN'T write a structured procedural program in a Pure-OO language like java without having those procedures be class methods.
Since all of your procedures are now class methods, your program is in a object, and hence, object-oriented.
You CAN NOT write a NON-OO program in a PURE-OO language. It CAN NOT BE DONE.
It may not be the style of OO that you are used to. In fact it may very well be a dirty hack of reimplementing a procedural program in an OO language with the least amount of code change possible.
It may be all public and disobey every rule of good OO design you've ever learned.
But, if it's composed of nothing but classes with methods, then it's Object Oriented. This is just a fundamental definition of the term Object Oriented as meaning comprised of Objects where objects are instances of classes. And in C++, yes, classes are very similar to namespaces, which are just buckets for methods and variables, but, guess what, that's all classes are too.
Again, it's a terminology problem. It's the difference between an OO program and a program written in a OO style. You MUST write an OO program when using a pure OO language. But you need not use OO style. You can write OO programs in a non-OO style. You cannot write non-OO programs in a pure OO language.
Justin Dubs
I think this is a problem of terminology.
A program that "contains objects", and is composed entirely of said "objects" CAN be considered OO, no matter what.
Style has nothing to do with classification.
Whether you use data-hiding, inheritance, encapsulation, polymorphism, [insert OO buzz-word here], is up to you.
It's still OO if your language is Pure-OO. That's what the name Pure-OO means for god's sake.
Yes, it might not be good OO-style. It may not be XP. But, good OO-style and XP are both fads. They have only been around for a few years and probably won't be around in the same form in a few more.
You can't say something isn't transportation because it doesn't get you to your destination the way you want to get there. It's transportation as long as it gets you there.
But, I do understand your point about Pure-OO languages not necessarily leading to GOOD OO programs. And I agree whole-heartedly. No language can make you a good programmer.
Justin Dubs
> One word - ew!
Why ew? Because of your limited programming experience with languages where this was eschewed?
In general, in computers, closure is a good thing. Ask any functional programmer. Ask any language theorist. Closure is good. To simplify closure, I am referring to having rules that don't have exceptions. Having a uniform representation for as much as possible.
In LISP data and code are stored the same way, as lists. This is the ultimate closure. Other languages implement other closures like having all data types be of a common type.
> What you really need is generics (as in C++ templates).
Lord God NO! Don't you EVER use C++ templates as an example of generics again. C++ templates are an attrocity. What you want is generic methods with multiple-dispatch. Look at Lisp's CLOS, or Dylan.
> However, that wouldn't make all Java programs "object-oriented programs",
Explain? How can you write a Non-OO program in a Pure-OO language? Cause, you see, it's not possible. You can write a program that isn't in the OO style that you think of when you think of OO. But you can't write a program that has data that isn't an "object" in a Pure-OO language.
> I have a suspicion that it might impact things like the JNI too
JNI would be as fine as it is now (yuch). Even the "float" class has to have an internal variable that actually stores the float.
Justin Dubs