General Question: Are Shading Languages/shaders object-oriented? - opengl

I am currently in an apprenticeship and one of the trainers said "Shaders are object-oriented" as an example for object-orientated programming. To me it means HLSL & GLSL are object-oriented languages.
I never thought of shaders as object-oriented.
But now when I look at this: https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)
vec4 someVec;
someVec.x + someVec.y;
I also see object-orientation, because of the dot. Now I am confused.
I started doing OpenGL and GLSL 2 years ago, it never came to my mind that GLSL is object-oriented.
So I kind of missed out a major point.
I know that these shader-languages HLSL/GLSL derive from their assembly-predecessors.
Can somebody please state if GLSL is indeed object-oriented.

No, OpenGL Shading Language is not object orientated. There are no methods (or even inheritance and polymorphism) in glsl.
The data types behave more like a struct in C, than a class in C++. But of course there a additional options to Constructors and initialize the glsl data types respectively some special Vector and Matrix Operations and components can be accessed by Swizzling.
But that makes the language not to an Object-oriented language, because the concept of objects requires fields of data and procedures (methods) contained in an object. In glsl the general concept of methods is missing.

I also see object-orientation, because of the dot.
That's not what "object orientation" means. The dot is merely the "member access operator", and for all intents and purposes is a combination of some sort of "typecast", "pointer dereferencing" and "pointer arithmetic". All in quotes, because there are not actual pointers involved as far as language and compiler are concerned, but on the silicon level it really boils down to address offsets.
Object orientation means that you can derive classes from other classes, overload and overwrite methods, and so on. Like this (pseudocode)
class A begin
var foo
var bar
method spam()
endclass
class B inherits A begin
var eggs
var bacon
var mixture
method spam() begin
eggs -= bacon
A::spam()
end
method mix(seasoning) begin
mixture = eggs * bacon + seasoning
spam()
end
endclass

GLSL is not an object-oriented language, but it is possible to mimic object-oriented classes using structs with overloaded methods:
struct Rectangle { //define a "base class"
float width;
float height;
};
void new(inout Rectangle self,float width,float height){ //a "constructor"
self.width = width;
self.height = height;
}
float area(Rectangle r){ //an "instance method"
return r.width * r.height;
}
float perimeter(Rectangle r){ //an "instance method"
return (r.width + r.height)*2.;
}
struct Square{
Rectangle super; //Square is a "subclass" of Rectangle
float width;
float height;
};
void new(inout Square self,float width){ //constructor for Square
self.width = width;
self.height = width;
}
void super(inout Square self){ // copy instance variables to superclass
self.super.width = self.width;
self.super.height = self.height;
}
float area(Square self){ //"inherit" this method from the superclass
super(self);
return area(self.super);
}
float perimeter(Square self){ //"inherit" this method from the superclass
super(self);
return perimeter(self.super);
}
void example(){
Rectangle r;
new(r,3.,4.); //initialize an instance of Rectangle
float rectangle_area = area(r); //call an instance method
float rectangle_perimeter = perimeter(r);
Square s;
new(s,3.); //initialize an instance of Square
float square_area = area(s); //call an instance method
float square_perimeter = perimeter(s);
}

Related

How can my class be provided some information about its environment?

Here's a code sample I wrote with encapsulation and composition in mind:
class Bullet {
private:
Vector2 position;
Vector2 speed;
public:
void move(float time_delta) {
position += speed * time_delta;
}
};
Basically, there's just a projectile moving in nowhere. However, a bullet can actually e. g. ricochet off a wall, having its speed changed significantly. Is there a good way of considering such interactions? I neither want my Bullet to know about "higher-rank" classes (which are supposed to use it themselves) nor write a single-use solution like this one:
template<typename F> void move(float time_delta, F collision_checker);
UPDATE: worth reading if you want this question narrowed. Here's a simplified example of the wished logic for moving Bullets (I don't exactly mean the Bullet::move() member function!) and their interactions with other entities:
Vector2 destination = bullet.position + bullet.speed * time_delta;
if (std::optional<Creature> target = get_first_creature(bullet.position, destination)) {
// decrease Bullet::speed depending on the target (and calculate the damage)
} else if (std::optional<Wall> obstacle = get_first_wall(bullet.position, destination)) {
// calculate the ricochet changing Bullet::position and Bullet::speed
}
All pieces of code represented by comments are supposed to use some properties of the Creature and Wall classes.
From a design point of view, it is probably best if your bullet doesn't know how to detect when it's ... passing_through an obstacle (scnr). So it might be better to turn your Bullet class in to a struct, i.e. have it behave like a thing that is acted upon instead of a thing that acts.
You can still add your convenience function but have it be non-mutating:
struct Bullet {
Vector2 position;
Vector2 speed;
Vector2 move(float time_delta) const {
return position + speed * time_delta;
}
};
This way you can compute the collisions from the calling scope:
auto dest = bullet.move(dt);
while (std::optional<Collision> const col = detectCollision(bullet.position,dest)) {
bullet.position = col->intersectPoint;
bullet.speed = col->reflectedSpeed;
dest = col->reflectDest;
}
bullet.position = dest;
Here detectCollision checks whether the line from the bullet's current position to the new position dest intersects with any obstacle and computes the parameters of the reflection. Effectively you zig-zag your way to the destination that will result from all successive ping-pongs of the bullet with potential obstacles.

How can I access to derived members from a pure virtual base class function?

I want to have a Collider interface class in which will have a overloaded -> operator to have access directy to the BoxCollider derived class. I want to have access to the members of box collider through the interface and chnage the type of collider at run-time.
So I thought of using templates:
template<typename T>
class ColliderV2 {
public:
virtual T* operator ->() = 0;
};
class BoxColliderV2 : public ColliderV2<BoxColliderV2> {
public:
float width;
float height;
BoxColliderV2* operator ->() {
return this;
}
};
int main()
{
ColliderV2<BoxColliderV2>* col = new BoxColliderV2;
(*col)->width = 1;
}
This works. But templates , as far as I know, will generate a brand new Collider class in compile-time filling T with Box Collider, correct? Thats why it worked. But later it prevents me from changing the collider type. I also thought of just making a virtual Collider class with Collider* operator->() ; overload in the derived class BoxCollider* operator->() ;
But if I tried :
Collider<BoxCollider>* col = new BoxCollider;
(*col)->width = 1; // won't work
doesn't work since Collider is not BoxCollider. And I don't want to dynamic_cast every possible collider type I could have. So, what can be done here?
As you've already found out, this doesn't work. Templates and runtime behavior are kind of contradicting mechanics. You can't create a common base class and let it act like a generic pointer to give you access to its derived types' members.
An interface specifies a contract against which you can code. You don't code against a specific implementation but the interface, so the interface has to provide all the members that you'd like to access. In your case this would result in width and height beeing part of ColliderV2 instead of BoxColliderV2. However this defeates the logic you are trying to mimic.
There are a few approaches that you can take:
Either make your collider type a variant, like
using ColliderType = std::variant<BoxColliderV2, MyOtherCollider, ...>;
and check for the actual type when you want to access the member
ColliderType myCollider = /* generate */;
if (auto boxCollider = std::get_if<BoxColliderV2>(&myCollider); boxCollider)
boxCollider->width = 0;
Or, keep the base class that you have, remove the operator-> and the template and do a dynamic cast on it:
ColliderV2* col = new BoxColliderV2;
if (auto boxCollider = dynamic_cast<BoxColliderV2*>(col); boxCollider)
boxCollider->width = 0;
You can also hide details like width or height behind more generic functions that are part of the interface. For example:
class ColliderV2 {
public:
virtual void setBounds(float width, float height) = 0;
};
class BoxColliderV2 : public ColliderV2 {
public:
void setBounds(float width, float height) override {
this->width = width;
this->height = height;
}
private:
float width;
float height;
};
int main()
{
ColliderV2* col = new BoxColliderV2;
col->setBounds(1, 1);
}
What you are trying to do is discouraged by C++. What you are trying to do is to change the type of something based on the return value of a function. The type system is designed to stop you from writing code like this.
One important restriction of a function is that can only return one type-of-thing. You can return one of a list of things if you wrap those possibilities in a class, and return that. In C++17, a ready-made class for this is std::variant. The restriction on this is that the list of things must be fixed (or a closed-set). If you want an arbitrary set of return values (open-set), you must use a different approach. You must restate your problem in terms a function that is done on the return value.
class BoxColliderV2 : public MyBaseCollider {
public:
void SetWidth(float new_width) override;
};
You may find this video useful. The bit of interest starts at around 40 minutes (but watch the whole video if you can). If you are interested in advice, I would suggest starting with std::variant, and if it works, move to virtual functions. Problems like collision detection get really complicated really quickly, and you will almost certainly require double dispatch at some stage. Start simple, because it's only going to get more complicated.
These excerpts from the ISO-Guidelines may help
1. When you change the semantic meaning of an operator, you make it
harder for other programmers to understand you code. guideline.
2. Dynamic casting is verbose and ugly, but deliberately so, because dynamic casting is dangerous, and should stand out. guideline
I think you are approaching the problem from the wrong direction. The purpose of an interface is that you don't have to know about the exact type or the implementation.
For example: You are using Axis-Aligned Bounding Boxes for collision detection. So, even if your CircleCollider uses a radius, you are still able to calculate its width and height from it. Now, you don't have to worry about if you are dealing with a BoxCollider or a CircleCollider, you have everything to make a Bounding Box.
class Collider
{
public:
virtual float x() const = 0;
virtual float y() const = 0;
virtual float width() const = 0;
virtual float height() const = 0;
};
class BoxCollider : public Collider
{
// Implementation...
};
class CircleCollider : public Collider
{
// Implementation...
};
Of course, you are maybe using something else, and not AABBs. I just wanted to demonstrate how you can use interfaces effectively.

Does a design pattern exist for enforcing rules on the data of a subclass?

Let's say a class represents a 3x3 matrix and takes 9 arbitrary numbers in its constructor and let that class have an inverse() method. Since NOT all matrices are invertible, the inverse() method returns an optional value (or a nullable pointer) which must be checked by callers at runtime.
However, certain 3x3 matrices are ALWAYS invertible, as long as the values in the matrix follow certain rules, e.g. 3D rotation matrices. We can codify that with a subclass, which does NOT allow direct construction but is constructed by using some special rules, e.g the rotation angle around a Cartesian axis.
The end result is this hierarchy, which should allow a client of the hierarchy to have compile time safety when using the subclass (e.g. a client is guaranteed that object.rotate(rotationMatrix.inverse()) will always work, assuming rotationMatrix is of type RotationMatrix):
class Matrix {
public:
Matrix(double e_0_0, double e_0_1, double e_0_2,
double e_1_0, double e_1_1, double e_1_2,
double e_2_0, double e_2_1, double e_2_2) {
...
}
std::unique_ptr<Matrix3x3> inverse() const {
if (isInvertible) {
return std::unique_ptr(new Matrix3x3(...));
}
return std::unique_ptr();
}
}
class RotationMatrix : public Matrix3x3 {
public:
static RotationMatrix getRotationAroundX(double angle) {
return asRotationMatrix(Matrix(1, 0, 0,
0, cos(angle), -sin(angle),
0, sin(angle), cos(angle)));
}
RotationMatrix inverse() const {
return asRotationMatrix(*Matrix::inverse().get()));
}
private:
static const RotationMatrix3D& asRotationMatrix(const Matrix3x3& matrix) {
return static_cast<const RotationMatrix3D&>(matrix);
}
}
So to break down the original question:
is there a pattern other than the one described above to achive this functionality?
if no other pattern exists, is there a way in C++ to prevent (or at least clearly signal to future developers) that the subclass MUST NOT introduce new state or constructors in order to avoid casting issues (e.g. slicing, etc)?
Here, you hit the circle/ellipse problem:
Better to have to distinct classes and use composition:
class RotationMatrix {
public:
static RotationMatrix getRotationAroundX(double angle) {
return { Matrix(1, 0, 0,
0, cos(angle), -sin(angle),
0, sin(angle), cos(angle))};
}
RotationMatrix inverse() const {
return {*Matrix::inverse().get()});
}
const Matrix3x3& AsMatrix() const { return matrix; }
private:
static RotationMatrix(const Matrix3x3& matrix) : matrix(matrix) {}
Matrix3x3 matrix;
};
These constraints should be enforced through the interface, in this case through the constructors and any potentially available mutators (setters). This is very much the pattern you describe.
To prevent future developers from messing with the internals of your class through inheritance, make the relevant data members, i.e. those you want to protect, inaccessible by declaring them private.
Since C++11 you can also declare your class final, so that nobody can inherit from it at all.
is there a way in C++ to prevent (or at least clearly signal to future developers) that the subclass MUST NOT introduce new state? Unfortunately the answer is NO. All the hierarchies in any OO languages use that as a common rule: a subclass can do all what its parent does and can add other methods and attributs
The better you can do if you have special requirements, is to write a documentation and clearly state them there.

C++ public and private datatypes

I am currently working on Chapter 7 in the book "Starting Out With C++ Early Objects" by the Pearson printing company.
I am unable to understand the function of the variable 'r' in this class declaration:
class Circle
{ private:
double radius;
public:
void setRadius(double r)
{ radius = r; }
double getArea()
{ return 3.14 * pow(radius, 2); }
};
Why can't I just write the 'radius' variable like this?
class Circle
{ private:
double radius;
double getArea()
{ return 3.14 * pow(radius, 2); }
};
I don't understand the function of the
public:
void setRadius(double r)
{ radius = r; }
Statement.
The technical reason is "because radius is private, hence inaccessible from outside the class".
So a change to radius must be some how managed by a public member function like SetRadius.
If the question now becomes "why designers did it that way, and did not simple make radius public?", well ... this is a never ending debate about how a proper object-oriented design should be an what has to be public and what not inside an object.
Traditional OOP school tends to make all data "private" and access or modify them through a variety of function to enforce what they call "encapsulation", and to have life easier in case the interface need to be extended to support eventual callbacks or events.
In this trivial simple case, well... all looks like a waste of energy (and without proper compiler optimization IS a waste of energy! In true physical sense). But may be they needed a uniform interface with something else.
As the functional behaviour of private is explained in other answers, directly accesing a private member outside the class will give you a compile-time error.
If you are asking why do we use setter functions and make some members private is a matter of design. For example; if you need the radius to be always positive number, you can write the set function as;
void setRadius(double r)
{
if(radius >= 0)
radius = r;
else
radius = 0;
}
Thus, you will have control over the values of the member when they are tried to be modified outside the class.
The radius is private. Without that function, you would not be able to set the radius from outside of the class. In order for the class to be useful, you would most likely want to be able to create objects of the type Circle and set their radius. Thus, you need some type of function in order to set that radius.
The easiest and most reasonable way to solve this is to supply a public member function inside the class Circle itself.
This can most easily be done using a setter, such as what you have shown. This allows you to set, and later change, the radius.
void SetRadius(float r)
{
radius = r;
}
You could also supply an extra argument to the constructor to ensure that a Circle always has its radius initialized with a user-supplied value, or at least set a default value in the declaration of radius (in C++11).
The concept of public private that no one can access the private variables just the class methods, and you can only access the public methods from your main function so ,the function setRadius is responsible to set the private variable of the radius
public:
void setRadius(double r)
{ radius = r; }
because the radius is a private variable so you have to create a public function inside the class to set that variable so you can set the radius when you create Circle object by :
this will work to set the radius in the main
Circle * test = new Circle;
test.setRadius(7);
but if you tried to set the radius directly by :
Circle * test = new Circle;
test.radius = 7;
it will crash the program Cannot access class private method

benefits of interface c++?

look at this code
#include<iostream>
using namespace std;
//Shape is an Interface Class. No data and everything pure virtual
class Shape {
public:
virtual void Area(int length, int breadth) = 0;
virtual void Perimeter(int length, int breadth) = 0;
//Note, no data
};
//Derived class - Inherits Shape as Public
class Rectangle : public Shape {
public:
void Area(int length, int breadth);
void Perimeter(int length, int breadth);
private:
int someData;
};
//Derived class - Inherits Shape as Public
class Triangle : public Shape {
public:
void Area(int length, int breadth);
void Perimeter(int length, int breadth);
private:
int someData;
};
int main()
{
Rectangle r;
Triangle t;
cout<<"\n\n";
r.Area(3,4);
r.Perimeter(3,4);
t.Area(3,4);
t.Perimeter(3,4);
cout<<"\n\n";
return 0;
}
void Rectangle::Area(int length, int breadth)
{
cout<<"\nThe Area of Rectangle for length = "<<length<<" and\
breadth = "<<breadth<<" is "<<(length * breadth)<<endl;
}
void Rectangle::Perimeter(int length, int breadth)
{
cout<<"\nThe Perimeter of Rectangle for length = "<<length<<" and\
breadth = "<<breadth<<" is "<<2 * (length + breadth)<<endl;
}
void Triangle::Area(int length, int breadth)
{
cout<<"\nThe Area of Triangle for length = "<<length<<" and\
breadth = "<<breadth<<" is "<<(length * breadth)/2<<endl;
}
void Triangle::Perimeter(int length, int breadth)
{
cout<<"\nThe Perimeter of Triangle for length = "<<length<<" and\
breadth = "<<breadth<<" is "<<(length * breadth)/3<<endl;
}
I use interface in the code , but my question is what i should use it and what is the benefits from it , no performance , no real needed it , why i should i use it ( the interfaces ) . what is the point to use it , an you explain it please .
and thank you !
Abstract interfaces separate the interface from the implementation. Just as pimpl idiom it
decreases compilation time, and
lets you change the implementation without breaking the ABI.
Both are important advantages in large programs.
An interface could be used to have, say, a vector of different Shape objects. Otherwise you couldn't have a collection that mixes triangles and rectangles for example. Or another class could have a Shape member, which could then either be a triangle or rectangle. These are just some examples.
Edit:
Let me give a concrete example. Say you have an interface called Car. Imagine you want to have a class Garage that has room for a single Car. You've implemented different types of cars, that all use the Car interface. Then the Garage class could be something like:
class Garage {
public:
Car getCar(); // returns _theCar
private:
Car _theCar:
}
A common mistake when programming C++ (and other object oriented languages) is to use inheritance too much. Interfaces is inheritance done right. The reason is that the strength of interfaces is to be able to handle objects of different type in another system as if they were the same type. Triangle and Circle can both be Shapes for instance and can be passed to a graphics engine for drawing on the screen.
The reason interfaces are 'better' than inheritance that also includes inherited functionality is that it quickly becomes very hard to understand what a class really does, to debug it and verify that the internal state of the objects cannot be destroyed by using the external methods.
The need for this type of structure where you use interfaces more than sporadically is hard to motivate in a small example, but becomes obvious when a projects grows big. Besides making things like I describes above possible they are also good to make it easier to test the program since you can then replace the implementation of part of your program (lets say the database access for instace) with a stubbed implementation and by doing that enable you to write automatic tests that verifies other parts of the program (processing the data for instance)
There are no performance reasons to choose interface over direct access to members, rather the opposite since you will call methods that are virtual. This is however a very minor performance penalty in the majority of cases.
Have a look here for more on C++ MI - Why should I avoid multiple inheritance in C++?.
Building up on the "3 Interfaces" section and ybungalobill's answer, consider the typical Observer pattern:
class MyClass : public IScreenListener
{
public:
MyClass()
{
PowerManager::RegisterScreenListener(*this);
}
// Overriding from IScreenListener
void OnScreenOn()
{
// do as you like
}
void OnScreenOff()
{
// do as you like
}
}
Here, the IScreenListener interface provides the two pure virtual methods OnScreenOff and OnScreenOn which are to be implemented in your code. This example is based on Bada's screen listener: it allows you to get notified by such events.
Of course, there are other benefits. Like hiding a code library implementation details from its users, and more.
Interfaces (Pure Abstract classes) provide general functionality. In your example, the class Shape is generic. Which means you cannot have a actual instance (or object) from the class Shape. Where as you can say a Rectangle is a Shape or a Triangle is a Shape. You cannot calculate Area or Perimeter of a Shape unless you know what Shape it is.
Interfaces (Pure Abstract classes) enforce a protocol that a class that is derived from it must implement all of its methods. Otherwise, it also becomes an interface. Interfaces pointers can be sent to functions or other classes and from there you can call the actual derived classes functionality.
For example, if there is a class called Animal from where you derive all animals like dogs, snakes, humans etc, you can send the array of Animal pointers (which are actually instances of it's derived classes) and then call the functionality like Run(), Walk(), Eat() etc. Animal in this case is generic class.