As long as you start with a foundation where A) you know what you're doing [not learning as you go] and B) you want to have multi platform support, it isn't all that hard.
(VERY simplified demo)
Say you have a call in DX to draw a graphic at a specific point :
DX_Draw_BMP(int x, int y, int z, (image *) Data);
but in Open GL you have something like this :
GL_Draw_Image(3dFloatPoint Position, (image *) Data);
The problem is that the locations are very different and the location systems, but the raw bitmap data is the same. (again, I know this isn't realistic, there are many more complicated steps involved, but trying to keep is simple for people to follow).
If you code for ONLY DX or OpenGL you could call which ever of these functions you want and it will work. But if you KNOW you want to support BOTH, you can't. Instead you need to do something where you create a wrapper function call :
DrawBitmap(float x, float y, float z, (img *) data);
For the DX version you have to convert the floats to ints, and the OpenGL version you need to create the 3dFloatPoint type so you end up with something like this :
DrawBitmap(x,y,z,data)
{
DX_Draw_BMP((int) x, (int) y, (int) z, data);
}
and then for OpenGL
DrawBitmap(x,y,z,data)
{
3dFloatPoint Pos = new 3dFloatPoint(x,y,z);
GL_Draw_Image(Pos, Data);
}
Each of these, typically will be in separate libraries and then you can link in if you want an OpenGL library or a DX library and the code will work.
(again, I'm trying to keep things simplified)
Sure one library may not be optimized, one may be slower then the other, some function calls will be better in one library then the other but overall they will be equivalent.
Then you ONLY write code using the newly defined DrawBitmap function and you don't need to care if you are operating in DirectX or OpenGL.
Same thing for Mac/PC code, you CAN make things more unified (note the word more). And with games, as you build up the engine, if you plan out a multi-platform development from the beginning, you can end up with the low level engine (the drawing, the memory processing and queuing and the thread processing) that is independent of the operating system and APIs below it.
This is how Blizzard has done their development. They planned from the beginning and built up their engine code so that all the low level components are system independent; then they can have another team focus on the game itself that runs above it.
Believe it or not, WoW pulled the original engine of Warcraft 3 to get started, yes they modified it, but it has the same basic core and I wouldn't be surprised if the low level drawing functions are identical. The game core, the AI, the User Interface, the data manipulation, etc is what is different
There are libraries out there that you can buy that will do much of the abstraction for you. Some of them are very good, they have Windows, Linux and OSX ports, some even goes further to support PS3, Nintendo and more. But when buying something like this, you don't have control over the optimization of the different segments and thus your performance on one system my be much worse then another.
Blizzard, if I recall correctly, developed their own library from the ground up. They started this before WoW, but heavily modified it for WoW. The reality is that this core engine was the long pole. Once they got the main engine up and running (networking, models, UI, AI, etc) the world came together VERY rapidly.
I give them a lot of credit for not pushing things out the door. They were willing to take a performance hit for all systems to give it support for all systems instead of hard coding things to get the best performance on one specific platform.