837 lines
18 KiB
C++
837 lines
18 KiB
C++
/*
|
|
* Copyright 2008 Haiku Inc. All rights reserved.
|
|
* Distributed under the terms of the MIT License.
|
|
*
|
|
* Authors:
|
|
* Alexandre Deckner
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Original Be Sample source modified to use a quaternion for the object's orientation
|
|
*/
|
|
|
|
/*
|
|
Copyright 1999, Be Incorporated. All Rights Reserved.
|
|
This file may be used under the terms of the Be Sample Code License.
|
|
*/
|
|
|
|
#include "ObjectView.h"
|
|
|
|
#include <Application.h>
|
|
#include <Catalog.h>
|
|
#include <Cursor.h>
|
|
#include <InterfaceKit.h>
|
|
#include <FindDirectory.h>
|
|
|
|
#include "FPS.h"
|
|
#include "GLObject.h"
|
|
#include "ResScroll.h"
|
|
|
|
#undef B_TRANSLATION_CONTEXT
|
|
#define B_TRANSLATION_CONTEXT "ObjectView"
|
|
|
|
float displayScale = 1.0;
|
|
float depthOfView = 30.0;
|
|
float zRatio = 10.0;
|
|
|
|
float white[3] = {1.0, 1.0, 1.0};
|
|
float dimWhite[3] = {0.25, 0.25, 0.25};
|
|
float black[3] = {0.0, 0.0, 0.0};
|
|
float foggy[3] = {0.4, 0.4, 0.4};
|
|
float blue[3] = {0.0, 0.0, 1.0};
|
|
float dimBlue[3] = {0.0, 0.0, 0.5};
|
|
float yellow[3] = {1.0, 1.0, 0.0};
|
|
float dimYellow[3] = {0.5, 0.5, 0.0};
|
|
float green[3] = {0.0, 1.0, 0.0};
|
|
float dimGreen[3] = {0.0, 0.5, 0.0};
|
|
float red[3] = {1.0, 0.0, 0.0};
|
|
|
|
float* bgColor = black;
|
|
|
|
const char *kNoResourceError = B_TRANSLATE("The Teapot 3D model was "
|
|
"not found in application resources. "
|
|
"Please repair the program installation.");
|
|
|
|
struct light {
|
|
float *ambient;
|
|
float *diffuse;
|
|
float *specular;
|
|
};
|
|
|
|
|
|
light lights[] = {
|
|
{NULL, NULL, NULL},
|
|
{dimWhite, white, white},
|
|
{dimWhite, yellow, yellow},
|
|
{dimWhite, red, red},
|
|
{dimWhite, blue, blue},
|
|
{dimWhite, green, green}
|
|
};
|
|
|
|
|
|
|
|
long
|
|
signalEvent(sem_id event)
|
|
{
|
|
int32 c;
|
|
get_sem_count(event,&c);
|
|
if (c < 0)
|
|
release_sem_etc(event,-c,0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
long
|
|
setEvent(sem_id event)
|
|
{
|
|
int32 c;
|
|
get_sem_count(event,&c);
|
|
if (c < 0)
|
|
release_sem_etc(event,-c,0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
long
|
|
waitEvent(sem_id event)
|
|
{
|
|
acquire_sem(event);
|
|
|
|
int32 c;
|
|
get_sem_count(event,&c);
|
|
if (c > 0)
|
|
acquire_sem_etc(event,c,0,0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int32
|
|
simonThread(void* cookie)
|
|
{
|
|
ObjectView* objectView = reinterpret_cast<ObjectView*>(cookie);
|
|
BScreen screen(objectView->Window());
|
|
|
|
int noPause = 0;
|
|
while (acquire_sem_etc(objectView->quittingSem, 1, B_TIMEOUT, 0) == B_NO_ERROR) {
|
|
if (objectView->SpinIt()) {
|
|
objectView->DrawFrame(noPause);
|
|
release_sem(objectView->quittingSem);
|
|
noPause = 1;
|
|
} else {
|
|
release_sem(objectView->quittingSem);
|
|
noPause = 0;
|
|
waitEvent(objectView->drawEvent);
|
|
}
|
|
screen.WaitForRetrace();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
ObjectView::ObjectView(BRect rect, const char *name, ulong resizingMode,
|
|
ulong options)
|
|
: BGLView(rect, name, resizingMode, 0, options),
|
|
fHistEntries(0),
|
|
fOldestEntry(0),
|
|
fFps(true),
|
|
fLastGouraud(true),
|
|
fGouraud(true),
|
|
fLastZbuf(true),
|
|
fZbuf(true),
|
|
fLastCulling(true),
|
|
fCulling(true),
|
|
fLastLighting(true),
|
|
fLighting(true),
|
|
fLastFilled(true),
|
|
fFilled(true),
|
|
fLastPersp(false),
|
|
fPersp(false),
|
|
fLastTextured(false),
|
|
fTextured(false),
|
|
fLastFog(false),
|
|
fFog(false),
|
|
fForceRedraw(false),
|
|
fLastYXRatio(1),
|
|
fYxRatio(1)
|
|
{
|
|
fTrackingInfo.isTracking = false;
|
|
fTrackingInfo.pickedObject = NULL;
|
|
fTrackingInfo.buttons = 0;
|
|
fTrackingInfo.lastX = 0.0f;
|
|
fTrackingInfo.lastY = 0.0f;
|
|
fTrackingInfo.lastDx = 0.0f;
|
|
fTrackingInfo.lastDy = 0.0f;
|
|
|
|
fLastObjectDistance = fObjectDistance = depthOfView / 8;
|
|
quittingSem = create_sem(1, "quitting sem");
|
|
drawEvent = create_sem(0, "draw event");
|
|
|
|
TriangleObject *Tri = new TriangleObject(this);
|
|
if (Tri->InitCheck() == B_OK) {
|
|
fObjListLock.Lock();
|
|
fObjects.AddItem(Tri);
|
|
fObjListLock.Unlock();
|
|
} else {
|
|
BAlert *NoResourceAlert = new BAlert(B_TRANSLATE("Error"),
|
|
kNoResourceError, B_TRANSLATE("OK"), NULL, NULL,
|
|
B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_STOP_ALERT);
|
|
NoResourceAlert->SetFlags(NoResourceAlert->Flags() | B_CLOSE_ON_ESCAPE);
|
|
NoResourceAlert->Go();
|
|
delete Tri;
|
|
}
|
|
}
|
|
|
|
|
|
ObjectView::~ObjectView()
|
|
{
|
|
delete_sem(quittingSem);
|
|
delete_sem(drawEvent);
|
|
}
|
|
|
|
|
|
void
|
|
ObjectView::AttachedToWindow()
|
|
{
|
|
float position[] = {0.0, 3.0, 3.0, 0.0};
|
|
float position1[] = {-3.0, -3.0, 3.0, 0.0};
|
|
float position2[] = {3.0, 0.0, 0.0, 0.0};
|
|
float local_view[] = {0.0, 0.0};
|
|
// float ambient[] = {0.1745, 0.03175, 0.03175};
|
|
// float diffuse[] = {0.61424, 0.10136, 0.10136};
|
|
// float specular[] = {0.727811, 0.626959, 0.626959};
|
|
// rgb_color black = {0, 0, 0, 255};
|
|
BRect bounds = Bounds();
|
|
|
|
BGLView::AttachedToWindow();
|
|
Window()->SetPulseRate(100000);
|
|
|
|
LockGL();
|
|
|
|
glEnable(GL_DITHER);
|
|
glEnable(GL_CULL_FACE);
|
|
glCullFace(GL_BACK);
|
|
glDepthFunc(GL_LESS);
|
|
|
|
glShadeModel(GL_SMOOTH);
|
|
|
|
glLightfv(GL_LIGHT0, GL_POSITION, position);
|
|
glLightfv(GL_LIGHT0 + 1, GL_POSITION, position1);
|
|
glLightfv(GL_LIGHT0 + 2, GL_POSITION, position2);
|
|
glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);
|
|
|
|
glEnable(GL_LIGHT0);
|
|
glLightfv(GL_LIGHT0, GL_SPECULAR, lights[lightWhite].specular);
|
|
glLightfv(GL_LIGHT0, GL_DIFFUSE,lights[lightWhite].diffuse);
|
|
glLightfv(GL_LIGHT0, GL_AMBIENT,lights[lightWhite].ambient);
|
|
glEnable(GL_LIGHT1);
|
|
glLightfv(GL_LIGHT1, GL_SPECULAR, lights[lightBlue].specular);
|
|
glLightfv(GL_LIGHT1, GL_DIFFUSE,lights[lightBlue].diffuse);
|
|
glLightfv(GL_LIGHT1, GL_AMBIENT,lights[lightBlue].ambient);
|
|
|
|
glFrontFace(GL_CW);
|
|
glEnable(GL_LIGHTING);
|
|
glEnable(GL_AUTO_NORMAL);
|
|
glEnable(GL_NORMALIZE);
|
|
|
|
glMaterialf(GL_FRONT, GL_SHININESS, 0.6 * 128.0);
|
|
|
|
glClearColor(bgColor[0], bgColor[1], bgColor[2], 1.0);
|
|
glColor3f(1.0, 1.0, 1.0);
|
|
|
|
glViewport(0, 0, (GLint)bounds.IntegerWidth() + 1,
|
|
(GLint)bounds.IntegerHeight() + 1);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
|
|
float scale = displayScale;
|
|
glOrtho(-scale, scale, -scale, scale, -scale * depthOfView,
|
|
scale * depthOfView);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
UnlockGL();
|
|
|
|
fDrawThread = spawn_thread(simonThread, "Simon", B_NORMAL_PRIORITY, this);
|
|
resume_thread(fDrawThread);
|
|
fForceRedraw = true;
|
|
setEvent(drawEvent);
|
|
}
|
|
|
|
|
|
void
|
|
ObjectView::DetachedFromWindow()
|
|
{
|
|
BGLView::DetachedFromWindow();
|
|
|
|
status_t dummy;
|
|
long locks = 0;
|
|
|
|
while (Window()->IsLocked()) {
|
|
locks++;
|
|
Window()->Unlock();
|
|
}
|
|
|
|
acquire_sem(quittingSem);
|
|
release_sem(drawEvent);
|
|
wait_for_thread(fDrawThread, &dummy);
|
|
release_sem(quittingSem);
|
|
|
|
while (locks--)
|
|
Window()->Lock();
|
|
}
|
|
|
|
|
|
void
|
|
ObjectView::Pulse()
|
|
{
|
|
Window()->Lock();
|
|
BRect parentBounds = Parent()->Bounds();
|
|
BRect bounds = Bounds();
|
|
parentBounds.OffsetTo(0, 0);
|
|
bounds.OffsetTo(0, 0);
|
|
if (bounds != parentBounds) {
|
|
ResizeTo(parentBounds.right - parentBounds.left,
|
|
parentBounds.bottom - parentBounds.top);
|
|
}
|
|
Window()->Unlock();
|
|
}
|
|
|
|
|
|
void
|
|
ObjectView::MessageReceived(BMessage* msg)
|
|
{
|
|
BMenuItem* item = NULL;
|
|
bool toggleItem = false;
|
|
|
|
switch (msg->what) {
|
|
case kMsgFPS:
|
|
fFps = (fFps) ? false : true;
|
|
msg->FindPointer("source", reinterpret_cast<void**>(&item));
|
|
item->SetMarked(fFps);
|
|
fForceRedraw = true;
|
|
setEvent(drawEvent);
|
|
break;
|
|
case kMsgAddModel:
|
|
{
|
|
TriangleObject *Tri = new TriangleObject(this);
|
|
if (Tri->InitCheck() == B_OK) {
|
|
fObjListLock.Lock();
|
|
fObjects.AddItem(Tri);
|
|
fObjListLock.Unlock();
|
|
} else {
|
|
BAlert *NoResourceAlert = new BAlert(B_TRANSLATE("Error"),
|
|
kNoResourceError, B_TRANSLATE("OK"), NULL, NULL,
|
|
B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_STOP_ALERT);
|
|
NoResourceAlert->SetFlags(NoResourceAlert->Flags() | B_CLOSE_ON_ESCAPE);
|
|
NoResourceAlert->Go();
|
|
delete Tri;
|
|
}
|
|
setEvent(drawEvent);
|
|
break;
|
|
}
|
|
case kMsgLights:
|
|
{
|
|
msg->FindPointer("source", reinterpret_cast<void**>(&item));
|
|
long lightNum = msg->FindInt32("num");
|
|
long color = msg->FindInt32("color");
|
|
BMenu *menu = item->Menu();
|
|
long index = menu->IndexOf(item);
|
|
menu->ItemAt(index)->SetMarked(true);
|
|
for (int i = 0; i < menu->CountItems(); i++) {
|
|
if (i != index)
|
|
menu->ItemAt(i)->SetMarked(false);
|
|
}
|
|
|
|
LockGL();
|
|
if (color != lightNone) {
|
|
glEnable(GL_LIGHT0 + lightNum - 1);
|
|
glLightfv(GL_LIGHT0 + lightNum - 1, GL_SPECULAR,
|
|
lights[color].specular);
|
|
glLightfv(GL_LIGHT0 + lightNum - 1, GL_DIFFUSE,
|
|
lights[color].diffuse);
|
|
glLightfv(GL_LIGHT0 + lightNum - 1, GL_AMBIENT,
|
|
lights[color].ambient);
|
|
} else {
|
|
glDisable(GL_LIGHT0 + lightNum - 1);
|
|
}
|
|
UnlockGL();
|
|
fForceRedraw = true;
|
|
setEvent(drawEvent);
|
|
break;
|
|
}
|
|
case kMsgGouraud:
|
|
fGouraud = !fGouraud;
|
|
toggleItem = true;
|
|
break;
|
|
case kMsgZBuffer:
|
|
fZbuf = !fZbuf;
|
|
toggleItem = true;
|
|
break;
|
|
case kMsgCulling:
|
|
fCulling = !fCulling;
|
|
toggleItem = true;
|
|
break;
|
|
case kMsgLighting:
|
|
fLighting = !fLighting;
|
|
toggleItem = true;
|
|
break;
|
|
case kMsgFilled:
|
|
fFilled = !fFilled;
|
|
toggleItem = true;
|
|
break;
|
|
case kMsgPerspective:
|
|
fPersp = !fPersp;
|
|
toggleItem = true;
|
|
break;
|
|
case kMsgFog:
|
|
fFog = !fFog;
|
|
toggleItem = true;
|
|
break;
|
|
}
|
|
|
|
if (toggleItem && msg->FindPointer("source", reinterpret_cast<void**>(&item)) == B_OK){
|
|
item->SetMarked(!item->IsMarked());
|
|
setEvent(drawEvent);
|
|
}
|
|
|
|
BGLView::MessageReceived(msg);
|
|
}
|
|
|
|
|
|
int
|
|
ObjectView::ObjectAtPoint(const BPoint &point)
|
|
{
|
|
LockGL();
|
|
glShadeModel(GL_FLAT);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_FOG);
|
|
glClearColor(black[0], black[1], black[2], 1.0);
|
|
glClear(GL_COLOR_BUFFER_BIT | (fZbuf ? GL_DEPTH_BUFFER_BIT : 0));
|
|
|
|
float idColor[3];
|
|
idColor[1] = idColor[2] = 0;
|
|
for (int i = 0; i < fObjects.CountItems(); i++) {
|
|
// to take into account 16 bits colorspaces,
|
|
// only use the 5 highest bits of the red channel
|
|
idColor[0] = (255 - (i << 3)) / 255.0;
|
|
reinterpret_cast<GLObject*>(fObjects.ItemAt(i))->Draw(true, idColor);
|
|
}
|
|
glReadBuffer(GL_BACK);
|
|
uchar pixel[256];
|
|
glReadPixels((GLint)point.x, (GLint)(Bounds().bottom - point.y), 1, 1,
|
|
GL_RGB, GL_UNSIGNED_BYTE, pixel);
|
|
int objNum = pixel[0];
|
|
objNum = (255 - objNum) >> 3;
|
|
|
|
EnforceState();
|
|
UnlockGL();
|
|
|
|
return objNum;
|
|
}
|
|
|
|
|
|
void
|
|
ObjectView::MouseDown(BPoint point)
|
|
{
|
|
GLObject* object = NULL;
|
|
|
|
BMessage *msg = Window()->CurrentMessage();
|
|
uint32 buttons = msg->FindInt32("buttons");
|
|
object = reinterpret_cast<GLObject*>(fObjects.ItemAt(ObjectAtPoint(point)));
|
|
|
|
if (object != NULL){
|
|
if (buttons == B_PRIMARY_MOUSE_BUTTON || buttons == B_SECONDARY_MOUSE_BUTTON) {
|
|
fTrackingInfo.pickedObject = object;
|
|
fTrackingInfo.buttons = buttons;
|
|
fTrackingInfo.isTracking = true;
|
|
fTrackingInfo.lastX = point.x;
|
|
fTrackingInfo.lastY = point.y;
|
|
fTrackingInfo.lastDx = 0.0f;
|
|
fTrackingInfo.lastDy = 0.0f;
|
|
fTrackingInfo.pickedObject->Spin(0.0f, 0.0f);
|
|
|
|
|
|
SetMouseEventMask(B_POINTER_EVENTS,
|
|
B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY);
|
|
|
|
BCursor grabbingCursor(B_CURSOR_ID_GRABBING);
|
|
SetViewCursor(&grabbingCursor);
|
|
} else {
|
|
ConvertToScreen(&point);
|
|
object->MenuInvoked(point);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ObjectView::MouseUp(BPoint point)
|
|
{
|
|
if (fTrackingInfo.isTracking) {
|
|
|
|
//spin the teapot on release, TODO: use a marching sum and divide by time
|
|
if (fTrackingInfo.buttons == B_PRIMARY_MOUSE_BUTTON
|
|
&& fTrackingInfo.pickedObject != NULL
|
|
&& (fabs(fTrackingInfo.lastDx) > 1.0f
|
|
|| fabs(fTrackingInfo.lastDy) > 1.0f) ) {
|
|
|
|
fTrackingInfo.pickedObject->Spin(0.5f * fTrackingInfo.lastDy, 0.5f * fTrackingInfo.lastDx);
|
|
|
|
setEvent(drawEvent);
|
|
}
|
|
|
|
//stop tracking
|
|
fTrackingInfo.isTracking = false;
|
|
fTrackingInfo.buttons = 0;
|
|
fTrackingInfo.pickedObject = NULL;
|
|
fTrackingInfo.lastX = 0.0f;
|
|
fTrackingInfo.lastY = 0.0f;
|
|
fTrackingInfo.lastDx = 0.0f;
|
|
fTrackingInfo.lastDy = 0.0f;
|
|
|
|
BCursor grabCursor(B_CURSOR_ID_GRAB);
|
|
SetViewCursor(&grabCursor);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ObjectView::MouseMoved(BPoint point, uint32 transit, const BMessage *msg)
|
|
{
|
|
if (fTrackingInfo.isTracking && fTrackingInfo.pickedObject != NULL) {
|
|
|
|
float dx = point.x - fTrackingInfo.lastX;
|
|
float dy = point.y - fTrackingInfo.lastY;
|
|
fTrackingInfo.lastX = point.x;
|
|
fTrackingInfo.lastY = point.y;
|
|
|
|
if (fTrackingInfo.buttons == B_PRIMARY_MOUSE_BUTTON) {
|
|
|
|
fTrackingInfo.pickedObject->Spin(0.0f, 0.0f);
|
|
fTrackingInfo.pickedObject->RotateWorldSpace(dx,dy);
|
|
fTrackingInfo.lastDx = dx;
|
|
fTrackingInfo.lastDy = dy;
|
|
|
|
setEvent(drawEvent);
|
|
|
|
} else if (fTrackingInfo.buttons == B_SECONDARY_MOUSE_BUTTON) {
|
|
|
|
float xinc = (dx * 2 * displayScale / Bounds().Width());
|
|
float yinc = (-dy * 2 * displayScale / Bounds().Height());
|
|
float zinc = 0;
|
|
|
|
if (fPersp) {
|
|
zinc = yinc * (fTrackingInfo.pickedObject->z / displayScale);
|
|
xinc *= -(fTrackingInfo.pickedObject->z * 4 / zRatio);
|
|
yinc *= -(fTrackingInfo.pickedObject->z * 4 / zRatio);
|
|
}
|
|
|
|
fTrackingInfo.pickedObject->x += xinc;
|
|
if (modifiers() & B_SHIFT_KEY)
|
|
fTrackingInfo.pickedObject->z += zinc;
|
|
else
|
|
fTrackingInfo.pickedObject->y += yinc;
|
|
|
|
fForceRedraw = true;
|
|
setEvent(drawEvent);
|
|
}
|
|
} else {
|
|
void* object = fObjects.ItemAt(ObjectAtPoint(point));
|
|
BCursor cursor(object != NULL
|
|
? B_CURSOR_ID_GRAB : B_CURSOR_ID_SYSTEM_DEFAULT);
|
|
SetViewCursor(&cursor);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ObjectView::FrameResized(float width, float height)
|
|
{
|
|
BGLView::FrameResized(width, height);
|
|
|
|
LockGL();
|
|
|
|
width = Bounds().Width();
|
|
height = Bounds().Height();
|
|
fYxRatio = height / width;
|
|
glViewport(0, 0, (GLint)width + 1, (GLint)height + 1);
|
|
|
|
// To prevent weird buffer contents
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
float scale = displayScale;
|
|
|
|
if (fPersp) {
|
|
gluPerspective(60, 1.0 / fYxRatio, 0.15, 120);
|
|
} else {
|
|
if (fYxRatio < 1) {
|
|
glOrtho(-scale / fYxRatio, scale / fYxRatio, -scale, scale, -1.0,
|
|
depthOfView * 4);
|
|
} else {
|
|
glOrtho(-scale, scale, -scale * fYxRatio, scale * fYxRatio, -1.0,
|
|
depthOfView * 4);
|
|
}
|
|
}
|
|
|
|
fLastYXRatio = fYxRatio;
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
UnlockGL();
|
|
|
|
fForceRedraw = true;
|
|
setEvent(drawEvent);
|
|
}
|
|
|
|
|
|
bool
|
|
ObjectView::RepositionView()
|
|
{
|
|
if (!(fPersp != fLastPersp) &&
|
|
!(fLastObjectDistance != fObjectDistance) &&
|
|
!(fLastYXRatio != fYxRatio)) {
|
|
return false;
|
|
}
|
|
|
|
LockGL();
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
float scale = displayScale;
|
|
|
|
if (fPersp) {
|
|
gluPerspective(60, 1.0 / fYxRatio, 0.15, 120);
|
|
} else {
|
|
if (fYxRatio < 1) {
|
|
glOrtho(-scale / fYxRatio, scale / fYxRatio, -scale, scale, -1.0,
|
|
depthOfView * 4);
|
|
} else {
|
|
glOrtho(-scale, scale, -scale * fYxRatio, scale * fYxRatio, -1.0,
|
|
depthOfView * 4);
|
|
}
|
|
}
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
UnlockGL();
|
|
|
|
fLastObjectDistance = fObjectDistance;
|
|
fLastPersp = fPersp;
|
|
fLastYXRatio = fYxRatio;
|
|
return true;
|
|
}
|
|
|
|
|
|
void
|
|
ObjectView::EnforceState()
|
|
{
|
|
glShadeModel(fGouraud ? GL_SMOOTH : GL_FLAT);
|
|
|
|
if (fZbuf)
|
|
glEnable(GL_DEPTH_TEST);
|
|
else
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
if (fCulling)
|
|
glEnable(GL_CULL_FACE);
|
|
else
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
if (fLighting)
|
|
glEnable(GL_LIGHTING);
|
|
else
|
|
glDisable(GL_LIGHTING);
|
|
|
|
if (fFilled)
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
else
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
|
|
if (fFog) {
|
|
glFogf(GL_FOG_START, 10.0);
|
|
glFogf(GL_FOG_DENSITY, 0.2);
|
|
glFogf(GL_FOG_END, depthOfView);
|
|
glFogfv(GL_FOG_COLOR, foggy);
|
|
glEnable(GL_FOG);
|
|
bgColor = foggy;
|
|
glClearColor(bgColor[0], bgColor[1], bgColor[2], 1.0);
|
|
} else {
|
|
glDisable(GL_FOG);
|
|
bgColor = black;
|
|
glClearColor(bgColor[0], bgColor[1], bgColor[2], 1.0);
|
|
}
|
|
}
|
|
|
|
|
|
bool
|
|
ObjectView::SpinIt()
|
|
{
|
|
bool changed = false;
|
|
|
|
if (fGouraud != fLastGouraud) {
|
|
LockGL();
|
|
glShadeModel(fGouraud ? GL_SMOOTH : GL_FLAT);
|
|
UnlockGL();
|
|
fLastGouraud = fGouraud;
|
|
changed = true;
|
|
}
|
|
|
|
if (fZbuf != fLastZbuf) {
|
|
LockGL();
|
|
if (fZbuf)
|
|
glEnable(GL_DEPTH_TEST);
|
|
else
|
|
glDisable(GL_DEPTH_TEST);
|
|
UnlockGL();
|
|
fLastZbuf = fZbuf;
|
|
changed = true;
|
|
}
|
|
|
|
if (fCulling != fLastCulling) {
|
|
LockGL();
|
|
if (fCulling)
|
|
glEnable(GL_CULL_FACE);
|
|
else
|
|
glDisable(GL_CULL_FACE);
|
|
UnlockGL();
|
|
fLastCulling = fCulling;
|
|
changed = true;
|
|
}
|
|
|
|
if (fLighting != fLastLighting) {
|
|
LockGL();
|
|
if (fLighting)
|
|
glEnable(GL_LIGHTING);
|
|
else
|
|
glDisable(GL_LIGHTING);
|
|
UnlockGL();
|
|
fLastLighting = fLighting;
|
|
changed = true;
|
|
}
|
|
|
|
if (fFilled != fLastFilled) {
|
|
LockGL();
|
|
if (fFilled) {
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
} else {
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
}
|
|
UnlockGL();
|
|
fLastFilled = fFilled;
|
|
changed = true;
|
|
}
|
|
|
|
if (fFog != fLastFog) {
|
|
if (fFog) {
|
|
glFogf(GL_FOG_START, 1.0);
|
|
glFogf(GL_FOG_DENSITY, 0.2);
|
|
glFogf(GL_FOG_END, depthOfView);
|
|
glFogfv(GL_FOG_COLOR, foggy);
|
|
glEnable(GL_FOG);
|
|
bgColor = foggy;
|
|
glClearColor(bgColor[0], bgColor[1], bgColor[2], 1.0);
|
|
} else {
|
|
glDisable(GL_FOG);
|
|
bgColor = black;
|
|
glClearColor(bgColor[0], bgColor[1], bgColor[2], 1.0);
|
|
}
|
|
fLastFog = fFog;
|
|
changed = true;
|
|
}
|
|
|
|
changed = changed || RepositionView();
|
|
changed = changed || fForceRedraw;
|
|
fForceRedraw = false;
|
|
|
|
for (int i = 0; i < fObjects.CountItems(); i++) {
|
|
bool hack = reinterpret_cast<GLObject*>(fObjects.ItemAt(i))->SpinIt();
|
|
changed = changed || hack;
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
|
|
void
|
|
ObjectView::DrawFrame(bool noPause)
|
|
{
|
|
LockGL();
|
|
glClear(GL_COLOR_BUFFER_BIT | (fZbuf ? GL_DEPTH_BUFFER_BIT : 0));
|
|
|
|
fObjListLock.Lock();
|
|
for (int i = 0; i < fObjects.CountItems(); i++) {
|
|
GLObject *object = reinterpret_cast<GLObject*>(fObjects.ItemAt(i));
|
|
if (object->Solidity() == 0)
|
|
object->Draw(false, NULL);
|
|
}
|
|
EnforceState();
|
|
for (int i = 0; i < fObjects.CountItems(); i++) {
|
|
GLObject *object = reinterpret_cast<GLObject*>(fObjects.ItemAt(i));
|
|
if (object->Solidity() != 0)
|
|
object->Draw(false, NULL);
|
|
}
|
|
fObjListLock.Unlock();
|
|
|
|
glDisable(GL_BLEND);
|
|
glDepthMask(GL_TRUE);
|
|
|
|
if (noPause) {
|
|
uint64 now = system_time();
|
|
float fps = 1.0 / ((now - fLastFrame) / 1000000.0);
|
|
fLastFrame = now;
|
|
int entry;
|
|
if (fHistEntries < HISTSIZE) {
|
|
entry = (fOldestEntry + fHistEntries) % HISTSIZE;
|
|
fHistEntries++;
|
|
} else {
|
|
entry = fOldestEntry;
|
|
fOldestEntry = (fOldestEntry + 1) % HISTSIZE;
|
|
}
|
|
|
|
fFpsHistory[entry] = fps;
|
|
|
|
if (fHistEntries > 5) {
|
|
fps = 0;
|
|
for (int i = 0; i < fHistEntries; i++)
|
|
fps += fFpsHistory[(fOldestEntry + i) % HISTSIZE];
|
|
|
|
fps /= fHistEntries;
|
|
|
|
if (fFps) {
|
|
glPushAttrib(GL_ENABLE_BIT | GL_LIGHTING_BIT);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glTranslatef(-0.9, -0.9, 0);
|
|
glScalef(0.10, 0.10, 0.10);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_BLEND);
|
|
glColor3f(1.0, 1.0, 0);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
FPS::drawCounter(fps);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPopMatrix();
|
|
glPopAttrib();
|
|
}
|
|
}
|
|
} else {
|
|
fHistEntries = 0;
|
|
fOldestEntry = 0;
|
|
}
|
|
SwapBuffers();
|
|
UnlockGL();
|
|
}
|