blender/intern/ghost/test/gears/GHOST_Test.cpp

753 lines
18 KiB
C++

/**
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/**
* Copyright (C) 2001 NaN Technologies B.V.
* Simple test file for the GHOST library.
* The OpenGL gear code is taken from the Qt sample code which,
* in turn, is probably taken from somewhere as well.
* @author Maarten Gribnau
* @date May 31, 2001
* Stereo code by Raymond de Vries, januari 2002
*/
#include <iostream>
#include <math.h>
#if defined(WIN32) || defined(__APPLE__)
#ifdef WIN32
#include <windows.h>
#include <atlbase.h>
#include <GL/gl.h>
#else // WIN32
// __APPLE__ is defined
#include <AGL/gl.h>
#endif // WIN32
#else // defined(WIN32) || defined(__APPLE__)
#include <GL/gl.h>
#endif // defined(WIN32) || defined(__APPLE__)
#include "STR_String.h"
#include "GHOST_Rect.h"
#include "GHOST_ISystem.h"
#include "GHOST_IEvent.h"
#include "GHOST_IEventConsumer.h"
#define LEFT_EYE 0
#define RIGHT_EYE 1
static bool nVidiaWindows; // very dirty but hey, it's for testing only
static void gearsTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time);
static class Application* fApp;
static GLfloat view_rotx=20.0, view_roty=30.0, view_rotz=0.0;
static GLfloat fAngle = 0.0;
static GHOST_ISystem* fSystem = 0;
void StereoProjection(float left, float right, float bottom, float top, float nearplane, float farplane,
float zero_plane, float dist,
float eye);
static void testTimerProc(GHOST_ITimerTask* /*task*/, GHOST_TUns64 time)
{
std::cout << "timer1, time=" << (int)time << "\n";
}
static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GLint teeth, GLfloat tooth_depth)
{
GLint i;
GLfloat r0, r1, r2;
GLfloat angle, da;
GLfloat u, v, len;
r0 = inner_radius;
r1 = outer_radius - tooth_depth/2.0;
r2 = outer_radius + tooth_depth/2.0;
const double pi = 3.14159264;
da = 2.0*pi / teeth / 4.0;
glShadeModel(GL_FLAT);
glNormal3f(0.0, 0.0, 1.0);
/* draw front face */
glBegin(GL_QUAD_STRIP);
for (i=0;i<=teeth;i++) {
angle = i * 2.0*pi / teeth;
glVertex3f(r0*cos(angle), r0*sin(angle), width*0.5);
glVertex3f(r1*cos(angle), r1*sin(angle), width*0.5);
glVertex3f(r0*cos(angle), r0*sin(angle), width*0.5);
glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5);
}
glEnd();
/* draw front sides of teeth */
glBegin(GL_QUADS);
da = 2.0*pi / teeth / 4.0;
for (i=0;i<teeth;i++) {
angle = i * 2.0*pi / teeth;
glVertex3f(r1*cos(angle), r1*sin(angle), width*0.5);
glVertex3f(r2*cos(angle+da), r2*sin(angle+da), width*0.5);
glVertex3f(r2*cos(angle+2*da), r2*sin(angle+2*da), width*0.5);
glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5);
}
glEnd();
glNormal3f(0.0, 0.0, -1.0);
/* draw back face */
glBegin(GL_QUAD_STRIP);
for (i=0;i<=teeth;i++) {
angle = i * 2.0*pi / teeth;
glVertex3f(r1*cos(angle), r1*sin(angle), -width*0.5);
glVertex3f(r0*cos(angle), r0*sin(angle), -width*0.5);
glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da), -width*0.5);
glVertex3f(r0*cos(angle), r0*sin(angle), -width*0.5);
}
glEnd();
/* draw back sides of teeth */
glBegin(GL_QUADS);
da = 2.0*pi / teeth / 4.0;
for (i=0;i<teeth;i++) {
angle = i * 2.0*pi / teeth;
glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da), -width*0.5);
glVertex3f(r2*cos(angle+2*da), r2*sin(angle+2*da), -width*0.5);
glVertex3f(r2*cos(angle+da), r2*sin(angle+da), -width*0.5);
glVertex3f(r1*cos(angle), r1*sin(angle), -width*0.5);
}
glEnd();
/* draw outward faces of teeth */
glBegin(GL_QUAD_STRIP);
for (i=0;i<teeth;i++) {
angle = i * 2.0*pi / teeth;
glVertex3f(r1*cos(angle), r1*sin(angle), width*0.5);
glVertex3f(r1*cos(angle), r1*sin(angle), -width*0.5);
u = r2*cos(angle+da) - r1*cos(angle);
v = r2*sin(angle+da) - r1*sin(angle);
len = sqrt(u*u + v*v);
u /= len;
v /= len;
glNormal3f(v, -u, 0.0);
glVertex3f(r2*cos(angle+da), r2*sin(angle+da), width*0.5);
glVertex3f(r2*cos(angle+da), r2*sin(angle+da), -width*0.5);
glNormal3f(cos(angle), sin(angle), 0.0);
glVertex3f(r2*cos(angle+2*da), r2*sin(angle+2*da), width*0.5);
glVertex3f(r2*cos(angle+2*da), r2*sin(angle+2*da), -width*0.5);
u = r1*cos(angle+3*da) - r2*cos(angle+2*da);
v = r1*sin(angle+3*da) - r2*sin(angle+2*da);
glNormal3f(v, -u, 0.0);
glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5);
glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da), -width*0.5);
glNormal3f(cos(angle), sin(angle), 0.0);
}
glVertex3f(r1*cos(0.0), r1*sin(0.0), width*0.5);
glVertex3f(r1*cos(0.0), r1*sin(0.0), -width*0.5);
glEnd();
glShadeModel(GL_SMOOTH);
/* draw inside radius cylinder */
glBegin(GL_QUAD_STRIP);
for (i=0;i<=teeth;i++) {
angle = i * 2.0*pi / teeth;
glNormal3f(-cos(angle), -sin(angle), 0.0);
glVertex3f(r0*cos(angle), r0*sin(angle), -width*0.5);
glVertex3f(r0*cos(angle), r0*sin(angle), width*0.5);
}
glEnd();
}
static void drawGearGL(int id)
{
static GLfloat pos[4] = { 5.0f, 5.0f, 10.0f, 1.0f };
static GLfloat ared[4] = { 0.8f, 0.1f, 0.0f, 1.0f };
static GLfloat agreen[4] = { 0.0f, 0.8f, 0.2f, 1.0f };
static GLfloat ablue[4] = { 0.2f, 0.2f, 1.0f, 1.0f };
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
switch (id)
{
case 1:
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ared);
gearGL(1.0f, 4.0f, 1.0f, 20, 0.7f);
break;
case 2:
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, agreen);
gearGL(0.5f, 2.0f, 2.0f, 10, 0.7f);
break;
case 3:
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ablue);
gearGL(1.3f, 2.0f, 0.5f, 10, 0.7f);
break;
default:
break;
}
glEnable(GL_NORMALIZE);
}
void RenderCamera()
{
glRotatef(view_rotx, 1.0, 0.0, 0.0);
glRotatef(view_roty, 0.0, 1.0, 0.0);
glRotatef(view_rotz, 0.0, 0.0, 1.0);
}
void RenderScene()
{
glPushMatrix();
glTranslatef(-3.0, -2.0, 0.0);
glRotatef(fAngle, 0.0, 0.0, 1.0);
drawGearGL(1);
glPopMatrix();
glPushMatrix();
glTranslatef(3.1f, -2.0f, 0.0f);
glRotatef(-2.0 * fAngle - 9.0, 0.0, 0.0, 1.0);
drawGearGL(2);
glPopMatrix();
glPushMatrix();
glTranslatef(-3.1f, 2.2f, -1.8f);
glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
glRotatef(2.0 * fAngle - 2.0, 0.0, 0.0, 1.0);
drawGearGL(3);
glPopMatrix();
}
static void View(GHOST_IWindow* window, bool stereo, int eye = 0)
{
window->activateDrawingContext();
GHOST_Rect bnds;
int noOfScanlines = 0, lowerScanline = 0;
int verticalBlankingInterval = 32; // hard coded for testing purposes, display device dependant
float left, right, bottom, top;
float nearplane, farplane, zeroPlane, distance;
float eyeSeparation = 0.62f;
window->getClientBounds(bnds);
// viewport
if(stereo)
{
if(nVidiaWindows)
{
// handled by nVidia driver so act as normal (explicitly put here since
// it -is- stereo)
glViewport(0, 0, bnds.getWidth(), bnds.getHeight());
}
else
{ // generic cross platform above-below stereo
noOfScanlines = (bnds.getHeight() - verticalBlankingInterval) / 2;
switch(eye)
{
case LEFT_EYE:
// upper half of window
lowerScanline = bnds.getHeight() - noOfScanlines;
break;
case RIGHT_EYE:
// lower half of window
lowerScanline = 0;
break;
}
}
}
else
{
noOfScanlines = bnds.getHeight();
lowerScanline = 0;
}
glViewport(0, lowerScanline, bnds.getWidth(), noOfScanlines);
// projection
left = -6.0;
right = 6.0;
bottom = -4.8f;
top = 4.8f;
nearplane = 5.0;
farplane = 60.0;
if(stereo)
{
zeroPlane = 0.0;
distance = 14.5;
switch(eye)
{
case LEFT_EYE:
StereoProjection(left, right, bottom, top, nearplane, farplane, zeroPlane, distance, -eyeSeparation / 2.0);
break;
case RIGHT_EYE:
StereoProjection(left, right, bottom, top, nearplane, farplane, zeroPlane, distance, eyeSeparation / 2.0);
break;
}
}
else
{
// left = -w;
// right = w;
// bottom = -h;
// top = h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(left, right, bottom, top, 5.0, 60.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -40.0);
}
glClearColor(.2f,0.0f,0.0f,0.0f);
}
void StereoProjection(float left, float right, float bottom, float top, float nearplane, float farplane,
float zero_plane, float dist,
float eye)
/* Perform the perspective projection for one eye's subfield.
The projection is in the direction of the negative z axis.
-6.0, 6.0, -4.8, 4.8,
left, right, bottom, top = the coordinate range, in the plane of zero
parallax setting, which will be displayed on the screen. The
ratio between (right-left) and (top-bottom) should equal the aspect
ratio of the display.
6.0, -6.0,
near, far = the z-coordinate values of the clipping planes.
0.0,
zero_plane = the z-coordinate of the plane of zero parallax setting.
14.5,
dist = the distance from the center of projection to the plane
of zero parallax.
-0.31
eye = half the eye separation; positive for the right eye subfield,
negative for the left eye subfield.
*/
{
float xmid, ymid, clip_near, clip_far, topw, bottomw, leftw, rightw,
dx, dy, n_over_d;
dx = right - left;
dy = top - bottom;
xmid = (right + left) / 2.0;
ymid = (top + bottom) / 2.0;
clip_near = dist + zero_plane - nearplane;
clip_far = dist + zero_plane - farplane;
n_over_d = clip_near / dist;
topw = n_over_d * dy / 2.0;
bottomw = -topw;
rightw = n_over_d * (dx / 2.0 - eye);
leftw = n_over_d *(-dx / 2.0 - eye);
/* Need to be in projection mode for this. */
glLoadIdentity();
glFrustum(leftw, rightw, bottomw, topw, clip_near, clip_far);
glTranslatef(-xmid - eye, -ymid, -zero_plane - dist);
return;
} /* stereoproj */
class Application : public GHOST_IEventConsumer {
public:
Application(GHOST_ISystem* system);
~Application(void);
virtual bool processEvent(GHOST_IEvent* event);
GHOST_ISystem* m_system;
GHOST_IWindow* m_mainWindow;
GHOST_IWindow* m_secondaryWindow;
GHOST_IWindow* m_fullScreenWindow;
GHOST_ITimerTask* m_gearsTimer, *m_testTimer;
GHOST_TStandardCursor m_cursor;
bool m_exitRequested;
bool stereo;
};
Application::Application(GHOST_ISystem* system)
: m_system(system), m_mainWindow(0), m_secondaryWindow(0), m_fullScreenWindow(0),
m_gearsTimer(0), m_testTimer(0), m_cursor(GHOST_kStandardCursorFirstCursor),
m_exitRequested(false), stereo(false)
{
fApp = this;
// Create the main window
STR_String title1 ("gears - main window");
m_mainWindow = system->createWindow(title1, 10, 64, 320, 200, GHOST_kWindowStateNormal,
GHOST_kDrawingContextTypeOpenGL, false, false);
if (!m_mainWindow) {
std::cout << "could not create main window\n";
exit(-1);
}
// Create a secondary window
STR_String title2 ("gears - secondary window");
m_secondaryWindow = system->createWindow(title2, 340, 64, 320, 200, GHOST_kWindowStateNormal,
GHOST_kDrawingContextTypeOpenGL, false, false);
if (!m_secondaryWindow) {
cout << "could not create secondary window\n";
exit(-1);
}
// Install a timer to have the gears running
m_gearsTimer = system->installTimer(0 /*delay*/, 20/*interval*/, gearsTimerProc, m_mainWindow);
}
Application::~Application(void)
{
// Dispose windows
if (m_system->validWindow(m_mainWindow)) {
m_system->disposeWindow(m_mainWindow);
}
if (m_system->validWindow(m_secondaryWindow)) {
m_system->disposeWindow(m_secondaryWindow);
}
}
bool Application::processEvent(GHOST_IEvent* event)
{
GHOST_IWindow* window = event->getWindow();
bool handled = true;
switch (event->getType()) {
/* case GHOST_kEventUnknown:
break;
case GHOST_kEventCursorButton:
std::cout << "GHOST_kEventCursorButton"; break;
case GHOST_kEventCursorMove:
std::cout << "GHOST_kEventCursorMove"; break;
*/
case GHOST_kEventWheel:
{
GHOST_TEventWheelData* wheelData = (GHOST_TEventWheelData*) event->getData();
if (wheelData->z > 0)
{
view_rotz += 5.f;
}
else
{
view_rotz -= 5.f;
}
}
break;
case GHOST_kEventKeyUp:
break;
case GHOST_kEventKeyDown:
{
GHOST_TEventKeyData* keyData = (GHOST_TEventKeyData*) event->getData();
switch (keyData->key) {
case GHOST_kKeyC:
{
int cursor = m_cursor;
cursor++;
if (cursor >= GHOST_kStandardCursorNumCursors) {
cursor = GHOST_kStandardCursorFirstCursor;
}
m_cursor = (GHOST_TStandardCursor)cursor;
window->setCursorShape(m_cursor);
}
break;
case GHOST_kKeyE:
{
int x = 200, y= 200;
m_system->setCursorPosition(x,y);
break;
}
case GHOST_kKeyF:
if (!m_system->getFullScreen()) {
// Begin fullscreen mode
GHOST_DisplaySetting setting;
setting.bpp = 16;
setting.frequency = 50;
setting.xPixels = 640;
setting.yPixels = 480;
m_system->beginFullScreen(setting, &m_fullScreenWindow, false /* stereo flag */);
}
else {
m_system->endFullScreen();
m_fullScreenWindow = 0;
}
break;
case GHOST_kKeyH:
window->setCursorVisibility(!window->getCursorVisibility());
break;
case GHOST_kKeyM:
{
bool down = false;
m_system->getModifierKeyState(GHOST_kModifierKeyLeftShift,down);
if (down) {
std::cout << "left shift down\n";
}
m_system->getModifierKeyState(GHOST_kModifierKeyRightShift,down);
if (down) {
std::cout << "right shift down\n"; }
m_system->getModifierKeyState(GHOST_kModifierKeyLeftAlt,down);
if (down) {
std::cout << "left Alt down\n";
}
m_system->getModifierKeyState(GHOST_kModifierKeyRightAlt,down);
if (down) {
std::cout << "right Alt down\n";
}
m_system->getModifierKeyState(GHOST_kModifierKeyLeftControl,down);
if (down) {
std::cout << "left control down\n";
}
m_system->getModifierKeyState(GHOST_kModifierKeyRightControl,down);
if (down) {
std::cout << "right control down\n";
}
}
break;
case GHOST_kKeyQ:
if (m_system->getFullScreen())
{
m_system->endFullScreen();
m_fullScreenWindow = 0;
}
m_exitRequested = true;
break;
case GHOST_kKeyS: // toggle mono and stereo
if(stereo)
stereo = false;
else
stereo = true;
break;
case GHOST_kKeyT:
if (!m_testTimer) {
m_testTimer = m_system->installTimer(0, 1000, testTimerProc);
}
else {
m_system->removeTimer(m_testTimer);
m_testTimer = 0;
}
break;
case GHOST_kKeyW:
if (m_mainWindow)
{
STR_String title;
m_mainWindow->getTitle(title);
title += "-";
m_mainWindow->setTitle(title);
}
break;
default:
break;
}
}
break;
case GHOST_kEventWindowClose:
{
GHOST_IWindow* window2 = event->getWindow();
if (window2 == m_mainWindow) {
m_exitRequested = true;
}
else {
m_system->disposeWindow(window2);
}
}
break;
case GHOST_kEventWindowActivate:
handled = false;
break;
case GHOST_kEventWindowDeactivate:
handled = false;
break;
case GHOST_kEventWindowUpdate:
{
GHOST_IWindow* window2 = event->getWindow();
if(!m_system->validWindow(window2))
break;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if(stereo)
{
View(window2, stereo, LEFT_EYE);
glPushMatrix();
RenderCamera();
RenderScene();
glPopMatrix();
View(window2, stereo, RIGHT_EYE);
glPushMatrix();
RenderCamera();
RenderScene();
glPopMatrix();
}
else
{
View(window2, stereo);
glPushMatrix();
RenderCamera();
RenderScene();
glPopMatrix();
}
window2->swapBuffers();
}
break;
default:
handled = false;
break;
}
return handled;
}
int main(int /*argc*/, char** /*argv*/)
{
nVidiaWindows = false;
// nVidiaWindows = true;
#ifdef WIN32
/* Set a couple of settings in the registry for the nVidia detonator driver.
* So this is very specific...
*/
if(nVidiaWindows)
{
LONG lresult;
HKEY hkey = 0;
DWORD dwd = 0;
//unsigned char buffer[128];
CRegKey regkey;
//DWORD keyValue;
// lresult = regkey.Open(HKEY_LOCAL_MACHINE, "SOFTWARE\\NVIDIA Corporation\\Global\\Stereo3D\\StereoEnable");
lresult = regkey.Open(HKEY_LOCAL_MACHINE, "SOFTWARE\\NVIDIA Corporation\\Global\\Stereo3D\\StereoEnable",
KEY_ALL_ACCESS);
if(lresult == ERROR_SUCCESS)
printf("Succesfully opened key\n");
#if 0
lresult = regkey.QueryValue(&keyValue, "StereoEnable");
if(lresult == ERROR_SUCCESS)
printf("Succesfully queried key\n");
#endif
lresult = regkey.SetValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\NVIDIA Corporation\\Global\\Stereo3D\\StereoEnable",
"1");
if(lresult == ERROR_SUCCESS)
printf("Succesfully set value for key\n");
regkey.Close();
if(lresult == ERROR_SUCCESS)
printf("Succesfully closed key\n");
// regkey.Write("2");
}
#endif // WIN32
// Create the system
GHOST_ISystem::createSystem();
fSystem = GHOST_ISystem::getSystem();
if (fSystem) {
// Create an application object
Application app (fSystem);
// Add the application as event consumer
fSystem->addEventConsumer(&app);
// Enter main loop
while (!app.m_exitRequested) {
//printf("main: loop\n");
fSystem->processEvents(true);
fSystem->dispatchEvents();
}
}
// Dispose the system
GHOST_ISystem::disposeSystem();
return 0;
}
static void gearsTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 /*time*/)
{
fAngle += 2.0;
view_roty += 1.0;
GHOST_IWindow* window = (GHOST_IWindow*)task->getUserData();
if (fApp->m_fullScreenWindow) {
// Running full screen
fApp->m_fullScreenWindow->invalidate();
}
else {
if (fSystem->validWindow(window)) {
window->invalidate();
}
}
}