OpenGL One Window 6 Views With Tao and C# (Multiple Views)
An OpenGl window with 6 different views

Introduction
This project is based on my previous project "OpenGL 3D Navigation2 With Tao and CSharp".
It shows how to create multiple views on a single window. I did create 6 different views of the same object (cube). It also has an example of Glut fonts and glRasterPos3f()
function.
Background
The goal of this program is to use multiple views in a single window. Therefore I'm going to explain a little bit about this subject. I also displayed fonts for each view. So I'm going to explain how I displayed the fonts. I'm not going to explain anything about how to navigate in 3D space because it is not the subject of this program.
This program (idea) is basically a copy of an existing idea - one window and multiple views. You can probably use multiple views in games with two or multiple players. Also you may use this in simulations where you want the simulation in a different perspective.
Dividing the window in multiple views is very simple. I will show how to do it below. The challenging part is to use this in your program.
Using Scissor
You start by enabling the SCISSOR_TEST
.
Gl.glEnable(Gl.GL_SCISSOR_TEST); // Enables SCISSOR
Second you set the ViewPort
, window size and location:
Gl.glViewport(0, height, width, height); // Set the viewPort
Gl.glScissor(0, height, width, height); // Divide the window
Now you write your code for this window. I have the same code six times with different parameters, because I did divide the window in 6 views.
Gl.glMatrixMode(Gl.GL_PROJECTION); // Set the Matrix mode
Gl.glLoadIdentity();
Glu.gluPerspective(75f, (float)width / (float)height, 0.10f, 500.0f); // Set the
// perspective
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glLoadIdentity();
Glu.gluLookAt(0.0, 0.0, 15.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); // Look at the
// new window at
// this position
drawCube(); // Draw the cube
Once you are done, make sure to disable the Scissor test.
Gl.glDisable(Gl.GL_SCISSOR_TEST);
Using Font
You need a small method with a for
loop to render a string
(text). The for
loop goes through the string
end sets the Font
type and size for each character. In this case, the font type is Times Roman and size 24.
// Used for the font that will be displayed
static void text(string c)
{
for (int i = 0; i < c.Length; i++)
{
// Render bitmap character
Glut.glutBitmapCharacter(Glut.GLUT_BITMAP_TIMES_ROMAN_24, c[i]);
}
}
Then you set the position for the string
(text) that you want to display and call your method with the string
that you want to display.
Gl.glRasterPos3f(-15, 19 , -15); // Set the position for the string (text)
text("Front"); // Display the text "Front"
Using the Code
About the Demo
I did include the Tao.OpenGL.dll and Tao.freeGlut.dll in the Demo folder. Normally it should execute without any problem. However, I did not test the demo on a different Operating System or computers so I don't know if it will work on your machine. You might need Vista and .NET Framework 2.0.
About the Source
I used Visual Studio 2005 (.NET Framework 2.0) C# and Tao (Tao.OpenGL
, Tao.freeGlut
). If you have VS 2005 and .NET Framework 2.0, you should not have any problem running the program from Visual Studio. Once you run the program, you can use the keyboard and mouse to navigate in 3D space.
Help
I did include lines through the x, y and z axis so that it will be easier to visualize. The dotted part is the negative side. The intersection of (x,y,z) is (0,0,0).
Line Colors
- Green for x axis
- Red for y axis
- Blue for z axis
Keys For Rotation (glRotatef())
- x rotates on x axis
- X rotates to opposite direction
- y rotates on y axis
- Y rotates to opposite direction
- z rotates on z axis
- Z rotates to opposite direction
- b,B rotates (+/-)90 degrees on x axis
- n,N rotates (+/-)90 degrees on y axis
- m,M rotates (+/-)90 degrees on z axis
Keys for Translation (glTranslatef())
- left_key - translates to left (x axis)
- right_key - translates to right (x axis)
- up_key - translates up (y axis)
- down_key - translates down (y axis)
- page_up - translates on z axis (zoom in)
- page_down - translates on z axis (zoom out)
Other Keys
- o,O brings everything to starting position
- F1 removes/shows the lines
- F2 rotates/stops the cube in x,y,z direction
Mouse
LeftMouseDown
translates cube in x and y direction (up/down,left/right)- Mouse wheel translates cube in +/- z direction (zoom in / zoom out)
Code
using System;
using System.Collections.Generic;
using System.Text;
using Tao.OpenGl;
using Tao.FreeGlut;
namespace OpenGLOneWindow6Views
{
sealed partial class OpenGLOneWindow6Views
{
// Declared static (no need for object reference)
static float X = 0.0f; // Translate screen to x direction (left or right)
static float Y = 0.0f; // Translate screen to y direction (up or down)
static float Z = 0.0f; // Translate screen to z direction (zoom in or out)
static float rotX = 0.0f; // Rotate screen on x axis
static float rotY = 0.0f; // Rotate screen on y axis
static float rotZ = 0.0f; // Rotate screen on z axis
static float rotLx = 0.0f; // Translate screen by using
// the glulookAt function (left or right)
static float rotLy = 0.0f; // Translate screen by using
// the glulookAt function (up or down)
static float rotLz = 0.0f; // Translate screen by using
// the glulookAt function (zoom in or out)
static bool lines = true; // Display x,y,z lines (coordinate lines)
static bool rotation = false; // Rotate if F2 is pressed
static int old_x, old_y; // Used for mouse event
static int mousePressed; // Check which botton is pressed
// Used for the font that will be displayed
static void text(string c)
{
for (int i = 0; i < c.Length; i++)
{
// Render bitmap character
Glut.glutBitmapCharacter(Glut.GLUT_BITMAP_TIMES_ROMAN_24, c[i]);
}
}
// Draw the lines (x,y,z)
static void draw()
{
int width = Glut.glutGet(Glut.GLUT_WINDOW_WIDTH); // Get the windows width
int height = Glut.glutGet(Glut.GLUT_WINDOW_HEIGHT); // Get the windows height
width = (width + 1) / 3; // 3 OpenGL windows side
// by side
height = (height + 1) / 2; // 2 OpenGl windows up
// and down
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT); // Clear Color
// and Depth Buffer
Gl.glEnable(Gl.GL_SCISSOR_TEST); // Enable Scissor Test for multiple view
// First window (Front view)
Gl.glViewport(0, height, width, height); // Set the viewPort
Gl.glScissor(0, height, width, height); // Divide the window
setWindow(width, height);
Glu.gluLookAt(0.0f , 0.0f , 15.0f , 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f); // Look at the new window at this position
drawCube(); // Draw the cube
Gl.glRasterPos3f(-15, 19, -15); // Set the position for the string (text)
text("Front"); // Display the text "Front"
// Second Window (Back View)
Gl.glViewport(0, 0, width, height);
Gl.glScissor(0, 0, width, height);
setWindow(width, height);
Glu.gluLookAt(0.0f, 0.0f , -15.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
drawCube();
Gl.glRasterPos3f(15.0f , 19.0f , 15.0f);
text("Back");
// Third window (Right View)
Gl.glViewport(width, height, width, height);
Gl.glScissor(width, height, width, height);
setWindow(width, height);
Glu.gluLookAt(15.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
drawCube();
Gl.glRasterPos3f(-15.0f, 19.0f, 15.0f);
text("Right");
// Forth Window (Left View)
Gl.glViewport(width, 0, width, height);
Gl.glScissor(width, 0, width, height);
setWindow(width, height);
Glu.gluLookAt(-15.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
drawCube();
Gl.glRasterPos3f(15.0f, 19.0f, -15.0f);
text("Left");
// Fifth window (Upside down view)
Gl.glViewport(2 * width, height, width, height);
Gl.glScissor(2 * width, height, width, height);
setWindow(width, height);
Glu.gluLookAt(0.0f , 15.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f);
drawCube();
Gl.glRasterPos3f(-15.0f, -15.0f, -19.0f);
text("Up");
// Sixth window bottom up view
Gl.glViewport(2 * width, 0, width, height);
Gl.glScissor(2 * width, 0, width, height);
setWindow(width, height);
Glu.gluLookAt(0.0f, -15.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f);
drawCube();
Gl.glRasterPos3f(15.0f, 15.0f, -19.0f);
text("Bottom");
Gl.glDisable(Gl.GL_SCISSOR_TEST);
Glut.glutSwapBuffers();
}
static void setWindow(float width, float height)
{
Gl.glMatrixMode(Gl.GL_PROJECTION); // Set the Matrix mode
Gl.glLoadIdentity();
Glu.gluPerspective(75.0f, (float)width /
(float)height, 0.10f, 500.0f); // Set the perspective
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glLoadIdentity();
}
static void drawCube()
{
// Clear the Color Buffer and Depth Buffer
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
Gl.glPushMatrix(); // It is important to push the Matrix
// before calling glRotatef and glTranslatef
Gl.glRotatef(rotX, 1.0f, 0.0f, 0.0f); // Rotate on x
Gl.glRotatef(rotY, 0.0f, 1.0f, 0.0f); // Rotate on y
Gl.glRotatef(rotZ, 0.0f, 0.0f, 1.0f); // Rotate on z
if (rotation) // If F2 is pressed update x,y,z for rotation of the cube
{
rotX += 0.2f;
rotY += 0.2f;
rotZ += 0.2f;
}
Gl.glTranslatef(X, Y, Z); // Translates the screen left or right,
// up or down or zoom in zoom out
if (lines) // If F1 is pressed don't draw the lines
{
// Draw the positive side of the lines x,y,z
Gl.glBegin(Gl.GL_LINES);
Gl.glColor3f(0.0f, 1.0f, 0.0f); // Green for x axis
Gl.glVertex3f(0f, 0f, 0f);
Gl.glVertex3f(10f, 0f, 0f);
Gl.glColor3f(1.0f, 0.0f, 0.0f); // Red for y axis
Gl.glVertex3f(0f, 0f, 0f);
Gl.glVertex3f(0f, 10f, 0f);
Gl.glColor3f(0.0f, 0.0f, 1.0f); // Blue for z axis
Gl.glVertex3f(0f, 0f, 0f);
Gl.glVertex3f(0f, 0f, 10f);
Gl.glEnd();
// Dotted lines for the negative sides of x,y,z coordinates
Gl.glEnable(Gl.GL_LINE_STIPPLE); // Enable line stipple to use
// a dotted pattern for the lines
Gl.glLineStipple(1, 0x0101); // Dotted stipple pattern for the lines
Gl.glBegin(Gl.GL_LINES);
Gl.glColor3f(0.0f, 1.0f, 0.0f); // Green for x axis
Gl.glVertex3f(-10f, 0f, 0f);
Gl.glVertex3f(0f, 0f, 0f);
Gl.glColor3f(1.0f, 0.0f, 0.0f); // Red for y axis
Gl.glVertex3f(0f, 0f, 0f);
Gl.glVertex3f(0f, -10f, 0f);
Gl.glColor3f(0.0f, 0.0f, 1.0f); // Blue for z axis
Gl.glVertex3f(0f, 0f, 0f);
Gl.glVertex3f(0f, 0f, -10f);
Gl.glEnd();
Gl.glDisable(Gl.GL_LINE_STIPPLE); // Disable the line stipple
}
// Drawing 3D cube
// Front side
Gl.glBegin(Gl.GL_POLYGON);
Gl.glColor3f(0.0f, 0.0f, 1.0f); // Set color to blue
Gl.glVertex3f(3.0f, 3.0f, 3.0f);
Gl.glColor3f(1.0f, 0.0f, 0.0f); // Set color to red
Gl.glVertex3f(3.0f, -3.0f, 3.0f);
Gl.glColor3f(0.0f,0.0f, 1.0f);
Gl.glVertex3f(-3.0f, -3.0f, 3.0f);
Gl.glColor3f(1.0f, 0.0f, 0.0f);
Gl.glVertex3f(-3.0f, 3.0f, 3.0f);
Gl.glEnd();
// Back side
Gl.glBegin(Gl.GL_POLYGON);
Gl.glColor3f(0.5f, 0.0f, .0f);
Gl.glVertex3f(3.0f, 3.0f, -3.0f);
Gl.glColor3f(0.0f, 0.0f, 1.0f);
Gl.glVertex3f(3.0f, -3.0f, -3.0f);
Gl.glColor3f(0.5f, 0.0f, 0.0f);
Gl.glVertex3f(-3.0f, -3.0f, -3.0f);
Gl.glColor3f(0.0f, 0.0f, 1.0f);
Gl.glVertex3f(-3.0f, 3.0f, -3.0f);
Gl.glEnd();
// Right side
Gl.glBegin(Gl.GL_POLYGON);
Gl.glColor3f(0.0f, 1.0f, 0.0f);
Gl.glVertex3f(3.0f, 3.0f, 3.0f);
Gl.glColor3f(0.0f, 0.0f, 1.0f);
Gl.glVertex3f(3.0f, 3.0f, -3.0f);
Gl.glColor3f(0.0f, 1.0f, 0.0f);
Gl.glVertex3f(3.0f, -3.0f, -3.0f);
Gl.glColor3f(0.0f, 0.0f, 1.0f);
Gl.glVertex3f(3.0f, -3.0f, 3.0f);
Gl.glEnd();
// Left Side
Gl.glBegin(Gl.GL_POLYGON);
Gl.glColor3f(0.0f, 0.0f, 1.0f);
Gl.glVertex3f(-3.0f, 3.0f, 3.0f);
Gl.glColor3f(0.0f, 1.0f, 0.0f);
Gl.glVertex3f(-3.0f, -3.0f, 3.0f);
Gl.glColor3f(0.0f, 0.0f, 1.0f);
Gl.glVertex3f(-3.0f, -3.0f, -3.0f);
Gl.glColor3f(0.0f, 1.0f, 0.0f);
Gl.glVertex3f(-3.0f, 3.0f, -3.0f);
Gl.glEnd();
// Upside
Gl.glBegin(Gl.GL_POLYGON);
Gl.glColor3f(0.0f, 0.0f, 1.0f);
Gl.glVertex3f(3.0f, 3.0f, 3.0f);
Gl.glColor3f(1.0f, 1.0f, 0.0f);
Gl.glVertex3f(3.0f, 3.0f, -3.0f);
Gl.glColor3f(0.0f, 0.0f, 1.0f);
Gl.glVertex3f(-3.0f, 3.0f, -3.0f);
Gl.glColor3f(1.0f, 1.0f, 0.0f);
Gl.glVertex3f(-3.0f, 3.0f, 3.0f);
Gl.glEnd();
// Bottom
Gl.glBegin(Gl.GL_POLYGON);
Gl.glColor3f(1.0f, 1.0f, 0.0f);
Gl.glVertex3f(3.0f, -3.0f, 3.0f);
Gl.glColor3f(0.0f, 0.0f, 1.0f);
Gl.glVertex3f(3.0f, -3.0f, -3.0f);
Gl.glColor3f(1.0f, 1.0f, 0.0f);
Gl.glVertex3f(-3.0f, -3.0f, -3.0f);
Gl.glColor3f(0.0f, 0.0f, 1.0f);
Gl.glVertex3f(-3.0f, -3.0f, 3.0f);
Gl.glEnd();
Gl.glColor3f(1.0f, 0.5f, 0.5f);
Glut.glutPostRedisplay(); // Redraw the scene
Gl.glPopMatrix(); // Don't forget to pop the Matrix
}
// This function is used for the navigation keys
public static void keyboard(byte key, int x, int y)
{
switch (key)
{
// x,X,y,Y,z,Z uses the glRotatef() function
case 120: // x // Rotates screen on x axis
rotX -= 2.0f;
break;
case 88: // X // Opposite way
rotX += 2.0f;
break;
case 121: // y // Rotates screen on y axis
rotY -= 2.0f;
break;
case 89: // Y // Opposite way
rotY += 2.0f;
break;
case 122: // z // Rotates screen on z axis
rotZ -= 2.0f;
break;
case 90: // Z // Opposite way
rotZ += 2.0f;
break;
// j,J,k,K,l,L uses the gluLookAt function for navigation
case 106: // j
rotLx -= 2.0f;
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glLoadIdentity();
Glu.gluLookAt(rotLx, rotLy, 15.0 + rotLz,
0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
break;
case 74: // J
rotLx += 2.0f;
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glLoadIdentity();
Glu.gluLookAt(rotLx, rotLy, 15.0 + rotLz, 0.0,
0.0, 0.0, 0.0, 1.0, 0.0);
break;
case 107: // k
rotLy -= 2.0f;
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glLoadIdentity();
Glu.gluLookAt(rotLx, rotLy, 15.0 + rotLz, 0.0,
0.0, 0.0, 0.0, 1.0, 0.0);
break;
case 75: // K
rotLy += 2.0f;
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glLoadIdentity();
Glu.gluLookAt(rotLx, rotLy, 15.0 + rotLz, 0.0,
0.0, 0.0, 0.0, 1.0, 0.0);
break;
case 108: // (l) It has a special case when the rotLZ becames less
// than -15 the screen is viewed from the opposite side
// therefore this if statement below does not allow
// rotLz be less than -15
if (rotLz + 14 >= 0)
rotLz -= 2.0f;
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glLoadIdentity();
Glu.gluLookAt(rotLx, rotLy, 15.0 + rotLz, 0.0,
0.0, 0.0, 0.0, 1.0, 0.0);
break;
case 76: // L
rotLz += 2.0f;
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glLoadIdentity();
Glu.gluLookAt(rotLx, rotLy, 15.0 + rotLz,
0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
break;
case 98: // b // Rotates on x axis by -90 degree
rotX -= 90.0f;
break;
case 66: // B // Rotates on y axis by 90 degree
rotX += 90.0f;
break;
case 110: // n // Rotates on y axis by -90 degree
rotY -= 90.0f;
break;
case 78: // N // Rotates on y axis by 90 degree
rotY += 90.0f;
break;
case 109: // m // Rotates on z axis by -90 degree
rotZ -= 90.0f;
break;
case 77: // M // Rotates on z axis by 90 degree
rotZ += 90.0f;
break;
case 111: // o // Resets all parameters
case 80: // O // Displays the cube in the starting position
rotation = false;
X = Y = 0.0f;
Z = 0.0f;
rotX = 0.0f;
rotY = 0.0f;
rotZ = 0.0f;
rotLx = 0.0f;
rotLy = 0.0f;
rotLz = 0.0f;
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glLoadIdentity();
Glu.gluLookAt(rotLx, rotLy, 15.0f + rotLz, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f);
break;
}
Glut.glutPostRedisplay(); // Redraw the scene
}
// Called on special key pressed
private static void specialKey(int key, int x, int y)
{
// Check which key is pressed
switch (key)
{
case Glut.GLUT_KEY_LEFT: // Rotate on x axis
X -= 2.0f;
break;
case Glut.GLUT_KEY_RIGHT: // Rotate on x axis (opposite)
X += 2.0f;
break;
case Glut.GLUT_KEY_UP: // Rotate on y axis
Y += 2.0f;
break;
case Glut.GLUT_KEY_DOWN: // Rotate on y axis (opposite)
Y -= 2.0f;
break;
case Glut.GLUT_KEY_PAGE_UP: // Rotate on z axis
Z -= 2.0f;
break;
case Glut.GLUT_KEY_PAGE_DOWN: // Rotate on z axis (opposite)
Z += 2.0f;
break;
case Glut.GLUT_KEY_F1: // Enable/Disable coordinate lines
lines = !lines;
break;
case Glut.GLUT_KEY_F2: // Enable/Disable automatic rotation
rotation = !rotation;
break;
default:
break;
}
Glut.glutPostRedisplay(); // Redraw the scene
}
// Capture the mouse click event
static void processMouseActiveMotion(int button, int state, int x, int y)
{
mousePressed = button; // Capture which mouse button is down
old_x = x; // Capture the x value
old_y = y; // Capture the y value
}
// Translate the x,y windows coordinates to OpenGL coordinates
static void processMouse(int x, int y)
{
if ((mousePressed == 0)) // If left mouse button is pressed
{
X = (x - old_x) / 15; // I did divide by 15 to adjust for a
// nice translation
Y = -(y - old_y) / 15;
}
Glut.glutPostRedisplay();
}
// Get the mouse wheel direction
static void processMouseWheel(int wheel, int direction, int x, int y)
{
Z += direction; // Adjust the Z value
Glut.glutPostRedisplay();
}
// Initialize the OpenGL window
static void init()
{
Gl.glShadeModel(Gl.GL_SMOOTH); // Set the shading model to smooth
Gl.glClearColor(0, 0, 0, 1.0f); // Clear the Color
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT); // Clear the
// Color and Depth Buffer
Gl.glClearDepth(1.0f); // Set the Depth buffer value (ranges[0,1])
Gl.glEnable(Gl.GL_DEPTH_TEST); // Enable Depth test
Gl.glDepthFunc(Gl.GL_LEQUAL); // If two objects on the same
// coordinate show the first drawn
Gl.glHint(Gl.GL_PERSPECTIVE_CORRECTION_HINT, Gl.GL_NICEST);
Gl.glDisable(Gl.GL_CULL_FACE);
}
// This function is called whenever the window size is changed
static void reshape(int w, int h)
{
Gl.glClearColor(0, 0, 0, 0.0f);
Gl.glViewport(0, 0, w, h); // Set the viewport
Gl.glMatrixMode(Gl.GL_PROJECTION); // Set the Matrix mode
Gl.glLoadIdentity();
Glu.gluPerspective(75f, (float)w / (float)h, 0.10f, 500.0f);
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glLoadIdentity();
Glu.gluLookAt(rotLx, rotLy, 15.0f + rotLz,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
}
// Main Starts
static void Main(string[] args)
{
Glut.glutInit(); // Initialize glut
Glut.glutInitDisplayMode(Glut.GLUT_DOUBLE | Glut.GLUT_RGB); // Setup display
// mode to double buffer and RGB color
Glut.glutInitWindowSize(600, 600); // Set the screen size
Glut.glutCreateWindow("OpenGL Multiple View"); // Windows capture
init(); // Call init()
Glut.glutReshapeFunc(reshape);
Glut.glutDisplayFunc(draw);
Glut.glutKeyboardFunc(new Glut.KeyboardCallback(keyboard)); // Set windows
// key callback
Glut.glutSpecialFunc(new Glut.SpecialCallback(specialKey)); // Set windows
// to specialKey callback
Glut.glutMouseFunc(new Glut.MouseCallback
(processMouseActiveMotion)); // Set window's to Mouse callback
Glut.glutMotionFunc(new Glut.MotionCallback
(processMouse)); // Set window's to motion callback
Glut.glutMouseWheelFunc(new Glut.MouseWheelCallback
(processMouseWheel));// Set window's to mouse motion callback
Glut.glutMainLoop();
}
}
}