Archived

This topic is now archived and is closed to further replies.

This topic is 5309 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I''m practicing on doing design before actually coding my project. I''ve wrote out all my classes that I plan to use. Then I stopped as I ran into a problem. It''s rather trivial but.. RenderObj->Draw(Object) or... Object->Draw(RenderObj) Which is correct OOP, or is there a correct way at all? I personally favor the first line and I try to keep all graphics in one class and only allow my objects (that can be rendered) to manipulate their own data. The reason I questioned this is because I''ve looked at many a source that uses the 2nd line.

Share this post


Link to post
Share on other sites
I think you mean either:

GfxEngine->RenderObject(Obj);

or

Object->Render();

Both are valid OOP approaches. For large classes (such as models) I''d suggest the latter - have the object handle its own drawing.

For smaller objects (such as coronas for lights, etc), the first solution should do well.

Never do anything that is a waste of time and be prepared to wage long tedious wars over this principle - Michael O''Connor

Share this post


Link to post
Share on other sites
No I knew what I was typing just a poor choice in naming my objects. My renderobject is going to essentially be a gfxengine and because Im using d3d I have to provide access to the device object which is a member. From sources I''ve studied the coders perfer to encapsulate all the d3d graphics code into a class and then when an object needs to be rendered they pass a device pointer to a draw function.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Personally, I would go with the 2nd, because that allows individual objects to decide how they want to draw themselves. Drawing will probably require access to a lot of private variables, so if you do "RenderObj->Draw(Object)" then you''ll have to make all those private variables available to RenderObj. On the other hand, if you do "Object->Draw(RenderObj)", then you''ll have to make sure that RenderObj makes available all of its drawing functions. And I think the second one would be easier. Plus I think the graphics engine will be a lot more efficient if every object uses the same primitive drawing functions (because you can optimize those functions).

But remember, the thing about OO design is that there are no easy answers. Maybe for the type of game you''re doing, the first version would be a lot easier, so take my advice with some salt.

A good OO design is really difficult to find, but really valuable once you find it.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
an addition to my last post: If all your objects are in the same format (like, they are all 3d models that are stored in the same way), then the first line would be easier. As in, if the RenderObj->Draw function does the same thing for every object, then go with that.

But if RenderObj->Draw just contains a big switch() statement that says "if Object is this class, then draw this...", then you''re better off with option 2.

Share this post


Link to post
Share on other sites
why not have both?
i do...
ie) my quadtree can choose which "nodes" of my map to render, and does so with a loop and some frustum information

-eldee
;another space monkey;
[ Forced Evolution Studios ]


::evolve::

Do NOT let Dr. Mario touch your genitals. He is not a real doctor!

Share this post


Link to post
Share on other sites
my solution was to have a listener between the gfx and objects..
this way you sort of have the best of both worlds the app still defines how things are drawn (can save alot of headaches with VB/texture switching) while you still have to call draw on each individual object.. the only real problem with this solution is the increase in virtual method overhead but i think its a small price to pay

Share this post


Link to post
Share on other sites
Basically, do you want a renderer that knows how to render objects or objects that know how to use a renderer to render themselves? For the former, you have to expose more information about your objects. For the latter, you have to expose more information about your renderer. Which will make your project''s code cleaner? That is the ultimate question, isn''t it? OO''s purpose is to make your code cleaner. Pick whichever is cleaner in your framework.

Share this post


Link to post
Share on other sites
I would go with the first because the second means each object has to know where to find the RenderObj.

It doesn''t make semantic sense to have an object draw itself. screen objects (sprite) don''t draw themselves. They tell the drawer how to draw them. Further, the object doesn''t know if its visible to the camera and I wouldn''t fancy the kludge I would have to write in order to find out of the object was visible!

Share this post


Link to post
Share on other sites
Like the AP said, if the renderer draws the objects, then it has to have access to internal information. That makes it tightly coupled to the object types. Every time you make a change to an object type or add a new type, you have to update the renderer. That is generally a bad thing.

Share this post


Link to post
Share on other sites
If the renderer is responsible for rendering objects (and the code is cleanly written) all you have to do to switch rendering api is to rewrite the renderer. If the objects have to draw themselves you have to alter (or inherit from) each object to use the new API.
So if supporting both DirectGraphics and OpenGL turns you on use method 1. Ofcourse there are tradeoffs to both approaches and the choice can not always be made until you know which type of graphics you want and what constitutes your objects.

[edited by - Thoooms on June 5, 2003 5:16:31 AM]

Share this post


Link to post
Share on other sites
Jambolo, the renderer needs no such thing. All objects should implement the drawable_object interface which could include everything you need to draw an object. That doesn''t have to be too tightly coupled.

Share this post


Link to post
Share on other sites
quote:
Original post by flangazor
Jambolo, the renderer needs no such thing. All objects should implement the drawable_object interface which could include everything you need to draw an object. That doesn''t have to be too tightly coupled.


That is fine as long as you are happy with being able to only render objects that can be represented by the drawable_object class.

And now I''m confused. I''m saying that it is a bad idea to put the code that draws different object types in the renderer, and it sounds like you are saying the same thing (since drawable_object would be implemented by each object).

Share this post


Link to post
Share on other sites
quote:
Original post by Zorbfish
RenderObj->Draw(Object)

or...

Object->Draw(RenderObj)


Which is correct OOP, or is there a correct way at all?

This problem arises in cruddy object systems which can only despatch over the dynamic type of the first object in the expression (that is, the one to the left of the `->''). This means that you are forced into considering behaviours as intrinsic to one environment or another, rather than as an interaction between different environments. The well-known example is the problem of collisions, where a collision occurs between two different objects, but can only be despatched on the dynamic type of the first object. Your problem is similar. The `Draw'' behaviour really involves two environments: the thing being drawn and the graphics engine doing the drawing. Common Lisp allows you to write generic functions which can despatch on the dynamic type of any number of arguments. You might have something like this:


(defgeneric draw (engine object))

Which declares a generic function called draw taking two arguments, `engine'' and `object''. Now you can specialise methods on the generic function, to provide for valid combinations of engine and object, and dynamic despatch comes into play for both arguments, meaning you don''t necessarily have to specialise for every single combination. For example, perhaps you have a couple of classes defined like so...


(defclass square ()
((length-of-side :initform 0 :accessor length-of-side)))
(defclass circle ()
((radius :initform 0 :accessor radius)))


And then you want to describe how instances of these classes are to be drawn in two different graphics engines...


(defmethod draw ((engine engine-variant-1) (object circle))
(... drawing logic ...))
(defmethod draw ((engine engine-variant-1) (object square))
(... drawing logic ...))
(defmethod draw ((engine engine-variant-2) (object circle))
(... drawing logic ...))
(defmethod draw ((engine engine-variant-2) (object square))
(... drawing logic ...))



Which I hope answers your question about the `correct OOP'' way of approaching the problem. It should be clear that it is the language you are using, rather than OOP itself, which is causing your problem.

Share this post


Link to post
Share on other sites
quote:
Original post by Jambolo
That is fine as long as you are happy with being able to only render objects that can be represented by the drawable_object class.

It would be pretty easy to be generic wrt what methods drawable_object provides. -if you so desired.
quote:

And now I''m confused. I''m saying that it is a bad idea to put the code that draws different object types in the renderer, and it sounds like you are saying the same thing (since drawable_object would be implemented by each object).

Yes. I suppose I wasn''t blindingly clear enough to people who don''t understand polymorphism.

Share this post


Link to post
Share on other sites
SabreMan: I'm not sure what you mean, but would the following C++ code not do the same as your lisp?

class Object
{
virtual void Draw(Renderer& r) = 0;
};

class Circle : Object
{
void Draw(Renderer& r)
{
r.render(this);
}
};

class Square :Object
{
void Draw(Renderer& r)
{
r.render(this);
}
};

class Renderer
{
virtual void Draw(Circle* c) = 0;
virtual void Draw(Square* s) = 0;
};

class Renderer1 : public Renderer
{
//implement Draw methods
};

class Renderer2 : public Renderer
{
//implement Draw methods
};

Maybe not as elegant, but the visitor pattern is easily understood and can be enhanced to do all sorts of things.

[edited by - Thoooms on June 5, 2003 9:39:11 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Thoooms
SabreMan: I''m not sure what you mean, but would the following C++ code not do the same as your lisp?

Please see this.
quote:

Maybe not as elegant, but the visitor pattern is easily understood and can be enhanced to do all sorts of things.

That''s close to saying `if I write enough supporting code, completely irrelevant to my immediate problem, then I can provide a rough approximation of the same concept'', which is effectively a fulfilment of Greenspun''s Tenth Rule. I wonder what you would find acceptable if I came up with a problem that despatches dynamically on three or four arguments? How about separation of concerns - each shape must know about the presence of some sort of Renderer. What happens when you decide you want to introduce serialisation for shapes? You then have to invent other irrelevant base classes, and disturb the hierarchy - Visitor doesn''t like unstable hierarchies.

Share this post


Link to post
Share on other sites
It seems people pretty much agree that neither option available in C++ is OO pure, so the question is more "Which is the lesser of two evils?". Maybe the best (assuming C++ remains the tool of choice) would be something like Syrillix said? It sounds a lot like the MVC paradigm (pattern?). Model and View are generic and probably follow the rules of OO, while the Controller says "screw purity", and encapsulates all the messy details. It''s no Lisp, but I''m assuming that Lisp is not an option for one reason or another.

Share this post


Link to post
Share on other sites