Initial revision
This was SVN commit r9.
This commit is contained in:
parent
f4f969482e
commit
5cc814759f
157
source/gui/CButton.cpp
Executable file
157
source/gui/CButton.cpp
Executable file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
CButton
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
*/
|
||||
|
||||
//#include "stdafx."
|
||||
#include "GUI.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// TEMP TODO Gee
|
||||
///extern nemFontNTF font;
|
||||
|
||||
// Offsets
|
||||
DECLARE_SETTINGS_INFO(SButtonSettings)
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Implementation Macros
|
||||
//-------------------------------------------------------------------
|
||||
#define _GUI_ADD_OFFSET(type, str, var) GUI_ADD_OFFSET(CButton, SButtonSettings, m_Settings, type, str, var)
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Constructor / Destructor
|
||||
//-------------------------------------------------------------------
|
||||
CButton::CButton()
|
||||
{
|
||||
// Settings defaults !
|
||||
m_Settings.m_Disabled = false;
|
||||
m_Settings.m_Font = "null";
|
||||
m_Settings.m_Sprite = "null";
|
||||
m_Settings.m_SpriteDisabled = "null";
|
||||
m_Settings.m_SpriteOver = "null";
|
||||
m_Settings.m_SpritePressed = "null";
|
||||
m_Settings.m_TextAlign = EAlign_Center;
|
||||
// m_Settings.m_TextColor = CColor();
|
||||
// m_Settings.m_TextColorDisabled;
|
||||
// m_Settings.m_TextColorOver;
|
||||
// m_Settings.m_TextColorPressed;
|
||||
m_Settings.m_TextValign = EValign_Center;
|
||||
m_Settings.m_ToolTip = "null";
|
||||
m_Settings.m_ToolTipStyle = "null";
|
||||
|
||||
|
||||
// Static! Only done once
|
||||
if (m_SettingsInfo.empty())
|
||||
{
|
||||
// Setup the base ones too
|
||||
SetupBaseSettingsInfo(m_SettingsInfo);
|
||||
|
||||
// Setup the new ones
|
||||
_GUI_ADD_OFFSET("bool", "disabled", m_Disabled)
|
||||
_GUI_ADD_OFFSET("string", "font", m_Font)
|
||||
_GUI_ADD_OFFSET("string", "sprite", m_Sprite)
|
||||
_GUI_ADD_OFFSET("string", "sprite-disabled", m_SpriteDisabled)
|
||||
_GUI_ADD_OFFSET("string", "sprite-over", m_SpriteOver)
|
||||
_GUI_ADD_OFFSET("string", "sprite-pressed", m_SpritePressed)
|
||||
_GUI_ADD_OFFSET("align", "textalign", m_TextAlign)
|
||||
_GUI_ADD_OFFSET("color", "textcolor", m_TextColor)
|
||||
_GUI_ADD_OFFSET("color", "textcolor-disabled", m_TextColorDisabled)
|
||||
_GUI_ADD_OFFSET("color", "textcolor-over", m_TextColorOver)
|
||||
_GUI_ADD_OFFSET("color", "textcolor-pressed", m_TextColorPressed)
|
||||
_GUI_ADD_OFFSET("valign", "textvalign", m_TextValign)
|
||||
_GUI_ADD_OFFSET("string", "tooltip", m_ToolTip)
|
||||
_GUI_ADD_OFFSET("string", "tooltip-style", m_ToolTipStyle)
|
||||
}
|
||||
}
|
||||
|
||||
CButton::~CButton()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Handles messages send from the CGUI
|
||||
// Input:
|
||||
// Message Message ID, GUIM_*
|
||||
//-------------------------------------------------------------------
|
||||
void CButton::HandleMessage(const EGUIMessage &Message)
|
||||
{
|
||||
// TODO REMOVE
|
||||
#define OUTPUT(x) g_console.submit("echo Object(<red>%s</>) <AADDFF>%s</>", m_Name.c_str(), #x);
|
||||
|
||||
CGUIButtonBehavior::HandleMessage(Message);
|
||||
|
||||
switch (Message)
|
||||
{
|
||||
case GUIM_PREPROCESS:
|
||||
break;
|
||||
|
||||
case GUIM_POSTPROCESS:
|
||||
break;
|
||||
|
||||
case GUIM_MOUSE_OVER:
|
||||
break;
|
||||
|
||||
case GUIM_MOUSE_ENTER:
|
||||
/// OUTPUT(GUIM_MOUSE_ENTER)
|
||||
break;
|
||||
|
||||
case GUIM_MOUSE_LEAVE:
|
||||
/// OUTPUT(GUIM_MOUSE_LEAVE)
|
||||
break;
|
||||
|
||||
case GUIM_MOUSE_PRESS_LEFT:
|
||||
/// OUTPUT(GUIM_MOUSE_PRESS_LEFT)
|
||||
break;
|
||||
|
||||
case GUIM_MOUSE_RELEASE_LEFT:
|
||||
/// OUTPUT(GUIM_MOUSE_RELEASE_LEFT)
|
||||
break;
|
||||
|
||||
case GUIM_PRESSED:
|
||||
/// OUTPUT(GUIM_PRESSED);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Draws the object
|
||||
// Input:
|
||||
// pInput Handler of keyboard and mouse
|
||||
//-------------------------------------------------------------------
|
||||
void CButton::Draw()
|
||||
{
|
||||
if (m_MouseHovering)
|
||||
{
|
||||
if (m_Pressed)
|
||||
glColor3f(0.7f, 0.f, 0.f);
|
||||
else
|
||||
glColor3f(0,1,(float)m_BaseSettings.m_Size.right/300.f);
|
||||
}
|
||||
else
|
||||
glColor3f((float)m_BaseSettings.m_Size.right/300.f,0,1);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(0.0f, 0.0f, GetBaseSettings().m_Z);
|
||||
|
||||
// Do this
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2i(GetBaseSettings().m_Size.right, GetBaseSettings().m_Size.bottom);
|
||||
glVertex2i(GetBaseSettings().m_Size.left, GetBaseSettings().m_Size.bottom);
|
||||
glVertex2i(GetBaseSettings().m_Size.left, GetBaseSettings().m_Size.top);
|
||||
glVertex2i(GetBaseSettings().m_Size.right, GetBaseSettings().m_Size.top);
|
||||
glEnd();
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glColor3f(0,0,0);
|
||||
/// font.print(GetBaseSettings().m_Size.left + 3, GetBaseSettings().m_Size.top - 15, LEFT, "Object: %s", GetName().c_str());
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
77
source/gui/CButton.h
Executable file
77
source/gui/CButton.h
Executable file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
GUI Object - Button
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
|
||||
--Overview--
|
||||
|
||||
GUI Object representing a simple button
|
||||
|
||||
--More info--
|
||||
|
||||
Check GUI.h
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CButton_H
|
||||
#define CButton_H
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Includes / Compiler directives
|
||||
//--------------------------------------------------------
|
||||
#include "GUI.h"
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Macros
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Types
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Declarations
|
||||
//--------------------------------------------------------
|
||||
|
||||
// Settings
|
||||
struct SButtonSettings
|
||||
{
|
||||
bool m_Disabled;
|
||||
CStr m_Font;
|
||||
CStr m_Sprite;
|
||||
CStr m_SpriteDisabled;
|
||||
CStr m_SpriteOver;
|
||||
CStr m_SpritePressed;
|
||||
EAlign m_TextAlign;
|
||||
CColor m_TextColor;
|
||||
CColor m_TextColorDisabled;
|
||||
CColor m_TextColorOver;
|
||||
CColor m_TextColorPressed;
|
||||
EValign m_TextValign;
|
||||
CStr m_ToolTip;
|
||||
CStr m_ToolTipStyle;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CButton : public CGUISettingsObject<SButtonSettings>, public CGUIButtonBehavior
|
||||
{
|
||||
GUI_OBJECT(CButton)
|
||||
|
||||
public:
|
||||
CButton();
|
||||
virtual ~CButton();
|
||||
|
||||
|
||||
|
||||
// Since we're doing multiple inheritance, this is to avoid error message
|
||||
virtual map_Settings GetSettingsInfo() const { return CGUISettingsObject<SButtonSettings>::m_SettingsInfo; }
|
||||
|
||||
// Handle Messages
|
||||
virtual void HandleMessage(const EGUIMessage &Message);
|
||||
|
||||
// Draw
|
||||
virtual void Draw();
|
||||
};
|
||||
|
||||
#endif
|
737
source/gui/CGUI.cpp
Executable file
737
source/gui/CGUI.cpp
Executable file
@ -0,0 +1,737 @@
|
||||
/*
|
||||
CGUI
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
*/
|
||||
|
||||
//#include "stdafx."
|
||||
#include "GUI.h"
|
||||
#include <string>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
///#include "nemesis.h"
|
||||
//#include incCONSOLE
|
||||
|
||||
#include <xercesc/dom/DOM.hpp>
|
||||
#include <xercesc/parsers/XercesDOMParser.hpp>
|
||||
#include <xercesc/framework/LocalFileInputSource.hpp>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
#include <xercesc/util/PlatformUtils.hpp>
|
||||
#include "XercesErrorHandler.h"
|
||||
|
||||
// namespaces used
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
using namespace std;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "xerces-c_2.lib")
|
||||
#endif
|
||||
|
||||
|
||||
#include "input.h"
|
||||
|
||||
// JW: how about having each object export hit_test(x,y),
|
||||
// instead of accessing the global mouse pos?
|
||||
int gui_mouse_x, gui_mouse_y;
|
||||
|
||||
// called from main loop when (input) events are received.
|
||||
// event is passed to other handlers if false is returned.
|
||||
|
||||
// JW: problem! this needs to be static, or not a member function
|
||||
// (it's a callback from the input distributor)
|
||||
bool InputHandler(const SDL_Event& ev)
|
||||
{
|
||||
if(ev.type == SDL_MOUSEMOTION)
|
||||
gui_mouse_x = ev.motion.x, gui_mouse_y = ev.motion.y;
|
||||
|
||||
// JW: (pre|post)process omitted; what're they for? why would we need any special button_released handling?
|
||||
|
||||
// Only one object can be hovered
|
||||
// check which one it is, if any !
|
||||
CGUIObject *pNearest = NULL;
|
||||
|
||||
// GUI<CGUIObject*>::RecurseObject(GUIRR_HIDDEN, m_BaseObject, &CGUIObject::ChooseMouseOverAndClosest, pNearest);
|
||||
|
||||
// Now we'll call UpdateMouseOver on *all* objects,
|
||||
// we'll input the one hovered, and they will each
|
||||
// update their own data and send messages accordingly
|
||||
// GUI<CGUIObject*>::RecurseObject(GUIRR_HIDDEN, m_BaseObject, &CGUIObject::UpdateMouseOver, pNearest);
|
||||
|
||||
if(pNearest)
|
||||
{
|
||||
/* if(ev.type == SDL_MOUSEBUTTONDOWN)
|
||||
pNearest->HandleMessage(GUIM_MOUSE_PRESS_LEFT); // JW: want to pass SDL button value, or translate?
|
||||
else if(ev.type == SDL_MOUSEBUTTONUP)
|
||||
pNearest->HandleMessage(GUIM_MOUSE_RELEASE_LEFT); // JW: want to pass SDL button value, or translate?
|
||||
*/
|
||||
}
|
||||
|
||||
// JW: what's the difference between mPress and mDown? what's the code below responsible for?
|
||||
/*/* // Generally if just mouse is clicked
|
||||
if (m_pInput->mDown(NEMM_BUTTON1) && pNearest)
|
||||
{
|
||||
pNearest->HandleMessage(GUIM_MOUSE_DOWN_LEFT);
|
||||
}
|
||||
*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Constructor / Destructor
|
||||
//-------------------------------------------------------------------
|
||||
CGUI::CGUI()
|
||||
{
|
||||
m_BaseObject = new CButton; // Big todo!
|
||||
m_BaseObject->SetGUI(this);
|
||||
|
||||
// This will make this invisible, not add
|
||||
//m_BaseObject->SetName(BASE_OBJECT_NAME);
|
||||
}
|
||||
|
||||
CGUI::~CGUI()
|
||||
{
|
||||
if (m_BaseObject)
|
||||
delete m_BaseObject;
|
||||
}
|
||||
|
||||
// Construct an object
|
||||
CGUIObject *CGUI::ConstructObject(const CStr &str)
|
||||
{
|
||||
if (m_ObjectTypes.count(str) > 0)
|
||||
return (*m_ObjectTypes[str])();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Initializes the GUI
|
||||
// Inputs:
|
||||
//
|
||||
//-------------------------------------------------------------------
|
||||
void CGUI::Initialize(/*/*CInput *pInput*/)
|
||||
{
|
||||
/// m_pInput = pInput;
|
||||
|
||||
// Add base types!
|
||||
AddObjectType("button", &CButton::ConstructObject);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Process the GUI, this should be run every loop after CInput
|
||||
// has been processed
|
||||
//-------------------------------------------------------------------
|
||||
void CGUI::Process()
|
||||
{
|
||||
/*/*
|
||||
|
||||
// GeeTODO / check if m_pInput is valid, otherwise return
|
||||
/// assert(m_pInput);
|
||||
|
||||
// Pre-process all objects
|
||||
try
|
||||
{
|
||||
GUI<EGUIMessage>::RecurseObject(0, m_BaseObject, &CGUIObject::HandleMessage, GUIM_PREPROCESS);
|
||||
}
|
||||
catch (PS_RESULT e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check mouse over
|
||||
try
|
||||
{
|
||||
// Only one object can be hovered
|
||||
// check which one it is, if any !
|
||||
CGUIObject *pNearest = NULL;
|
||||
|
||||
GUI<CGUIObject*>::RecurseObject(GUIRR_HIDDEN, m_BaseObject, &CGUIObject::ChooseMouseOverAndClosest, pNearest);
|
||||
|
||||
// Now we'll call UpdateMouseOver on *all* objects,
|
||||
// we'll input the one hovered, and they will each
|
||||
// update their own data and send messages accordingly
|
||||
GUI<CGUIObject*>::RecurseObject(GUIRR_HIDDEN, m_BaseObject, &CGUIObject::UpdateMouseOver, pNearest);
|
||||
|
||||
// If pressed
|
||||
if (m_pInput->mPress(NEMM_BUTTON1) && pNearest)
|
||||
{
|
||||
pNearest->HandleMessage(GUIM_MOUSE_PRESS_LEFT);
|
||||
}
|
||||
else
|
||||
// If released
|
||||
if (m_pInput->mRelease(NEMM_BUTTON1) && pNearest)
|
||||
{
|
||||
pNearest->HandleMessage(GUIM_MOUSE_RELEASE_LEFT);
|
||||
}
|
||||
|
||||
// Generally if just mouse is clicked
|
||||
if (m_pInput->mDown(NEMM_BUTTON1) && pNearest)
|
||||
{
|
||||
pNearest->HandleMessage(GUIM_MOUSE_DOWN_LEFT);
|
||||
}
|
||||
|
||||
}
|
||||
catch (PS_RESULT e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Post-process all objects
|
||||
try
|
||||
{
|
||||
GUI<EGUIMessage>::RecurseObject(0, m_BaseObject, &CGUIObject::HandleMessage, GUIM_POSTPROCESS);
|
||||
}
|
||||
catch (PS_RESULT e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Make all drawing calls of the GUI
|
||||
//-------------------------------------------------------------------
|
||||
void CGUI::Draw()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Recurse CGUIObject::Draw()
|
||||
GUI<>::RecurseObject(GUIRR_HIDDEN, m_BaseObject, &CGUIObject::Draw);
|
||||
}
|
||||
catch (PS_RESULT e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Shutdown all memory
|
||||
//-------------------------------------------------------------------
|
||||
void CGUI::Destroy()
|
||||
{
|
||||
// We can use the map to delete all
|
||||
// now we don't want to cancel all if one Destory fails
|
||||
map_pObjects::iterator it;
|
||||
for (it = m_pAllObjects.begin(); it != m_pAllObjects.end(); ++it)
|
||||
{
|
||||
try
|
||||
{
|
||||
it->second->Destroy();
|
||||
}
|
||||
catch (PS_RESULT e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
delete it->second;
|
||||
it->second = NULL;
|
||||
}
|
||||
|
||||
// Clear all
|
||||
m_pAllObjects.clear();
|
||||
m_Sprites.clear();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Adds an object to the GUI's object database
|
||||
// Input:
|
||||
// Name Name of object
|
||||
// pObject Object's pointer
|
||||
//
|
||||
// Return:
|
||||
// Throws PS_RESULT
|
||||
//-------------------------------------------------------------------
|
||||
void CGUI::AddObject(CGUIObject* pObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Add CGUI pointer
|
||||
GUI<CGUI*>::RecurseObject(0, pObject, &CGUIObject::SetGUI, this);
|
||||
|
||||
// Add child to base object
|
||||
m_BaseObject->AddChild(pObject);
|
||||
}
|
||||
catch (PS_RESULT e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Should be called when an object has been
|
||||
// This function is atomic, meaning if it throws anything, it will
|
||||
// have seen it through that nothing was ultimately changed.
|
||||
// Throws:
|
||||
// Whatever AddToPointersMap throws
|
||||
//-------------------------------------------------------------------
|
||||
void CGUI::UpdateObjects()
|
||||
{
|
||||
// We'll fill a temporary map until we know everything
|
||||
// succeeded
|
||||
map_pObjects AllObjects;
|
||||
|
||||
try
|
||||
{
|
||||
// Fill freshly
|
||||
GUI< map_pObjects >::RecurseObject(0, m_BaseObject, &CGUIObject::AddToPointersMap, AllObjects );
|
||||
}
|
||||
catch (PS_RESULT e)
|
||||
{
|
||||
// Throw the same error
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Else actually update the real one
|
||||
m_pAllObjects = AllObjects;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Check if an object exists by name
|
||||
// Input:
|
||||
// Name Object reference name
|
||||
//-------------------------------------------------------------------
|
||||
bool CGUI::ObjectExists(const CStr &Name) const
|
||||
{
|
||||
if (m_pAllObjects.count(Name))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Report XML Reading Error, should be called from within the
|
||||
// Xerces_* functions. These will not
|
||||
// Input:
|
||||
// str String explaining error
|
||||
//-------------------------------------------------------------------
|
||||
void CGUI::ReportParseError(const CStr &str, ...)
|
||||
{
|
||||
// Print header
|
||||
if (m_Errors==0)
|
||||
{
|
||||
/// g_nemLog("*** GUI Tree Creation Errors");
|
||||
}
|
||||
|
||||
// Important, set ParseError to true
|
||||
++m_Errors;
|
||||
|
||||
char buffer[512];
|
||||
va_list args;
|
||||
|
||||
// get arguments
|
||||
va_start(args, str);
|
||||
vsprintf(buffer, str.c_str(), args);
|
||||
va_end(args);
|
||||
|
||||
/// g_nemLog(" %s", buffer);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Adds an object to the GUI's object database
|
||||
// Input:
|
||||
// Filename XML filename
|
||||
//-------------------------------------------------------------------
|
||||
void CGUI::LoadXMLFile(const CStr &Filename)
|
||||
{
|
||||
// Reset parse error
|
||||
// we can later check if this has increased
|
||||
m_Errors = 0;
|
||||
|
||||
// Initialize XML library
|
||||
XMLPlatformUtils::Initialize();
|
||||
|
||||
// Create parser instance
|
||||
XercesDOMParser *parser = new XercesDOMParser();
|
||||
|
||||
bool ParseFailed = false;
|
||||
|
||||
if (parser)
|
||||
{
|
||||
// Setup parser
|
||||
parser->setValidationScheme(XercesDOMParser::Val_Auto);
|
||||
parser->setDoNamespaces(false);
|
||||
parser->setDoSchema(false);
|
||||
|
||||
// Set cosutomized error handler
|
||||
XercesErrorHandler *errorHandler = new XercesErrorHandler();
|
||||
parser->setErrorHandler(errorHandler);
|
||||
|
||||
parser->setCreateEntityReferenceNodes(false);
|
||||
|
||||
try
|
||||
{
|
||||
/// g_nemLog("*** Xerces XML Parsing Errors");
|
||||
|
||||
// Get main node
|
||||
LocalFileInputSource source( XMLString::transcode(Filename.c_str()) );
|
||||
|
||||
// parse
|
||||
parser->parse(source);
|
||||
|
||||
// Check how many errors
|
||||
ParseFailed = parser->getErrorCount() != 0;
|
||||
if (ParseFailed)
|
||||
{
|
||||
// TODO report for real!
|
||||
/// g_console.submit("echo Xerces XML Parsing Reports %d errors", parser->getErrorCount());
|
||||
}
|
||||
}
|
||||
catch (const XMLException& toCatch)
|
||||
{
|
||||
char* message = XMLString::transcode(toCatch.getMessage());
|
||||
/// g_console.submit("echo Exception message is: %s", message);
|
||||
XMLString::release(&message);
|
||||
}
|
||||
catch (const DOMException& toCatch)
|
||||
{
|
||||
char* message = XMLString::transcode(toCatch.msg);
|
||||
/// g_console.submit("echo Exception message is: %s", message);
|
||||
XMLString::release(&message);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
/// g_console.submit("echo Unexpected Exception");
|
||||
}
|
||||
|
||||
// Parse Failed?
|
||||
if (!ParseFailed)
|
||||
{
|
||||
DOMDocument *doc = parser->getDocument();
|
||||
DOMElement *node = doc->getDocumentElement();
|
||||
|
||||
// Check root element's (node) name so we know what kind of
|
||||
// data we'll be expecting
|
||||
string root_name = XMLString::transcode( node->getNodeName() );
|
||||
|
||||
if (root_name == "objects")
|
||||
{
|
||||
Xerces_ReadRootObjects(node);
|
||||
}
|
||||
else
|
||||
if (root_name == "sprites")
|
||||
{
|
||||
Xerces_ReadRootSprites(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now report if any other errors occured
|
||||
if (m_Errors > 0)
|
||||
{
|
||||
/// g_console.submit("echo GUI Tree Creation Reports %d errors", m_Errors);
|
||||
}
|
||||
|
||||
XMLPlatformUtils::Terminate();
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// XML Reading Xerces Specific Sub-Routines
|
||||
//===================================================================
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reads in the root element <objects></objects> (the DOMElement).
|
||||
// Input:
|
||||
// pElement The Xerces C++ Parser object that represents
|
||||
// the <objects>.
|
||||
//-------------------------------------------------------------------
|
||||
void CGUI::Xerces_ReadRootObjects(XERCES_CPP_NAMESPACE::DOMElement *pElement)
|
||||
{
|
||||
// Iterate main children
|
||||
// they should all be <object> elements
|
||||
DOMNodeList *children = pElement->getChildNodes();
|
||||
|
||||
for (int i=0; i<children->getLength(); ++i)
|
||||
{
|
||||
DOMNode *child = children->item(i);
|
||||
|
||||
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
|
||||
{
|
||||
// Read in this whole object into the GUI
|
||||
DOMElement *element = (DOMElement*)child;
|
||||
Xerces_ReadObject(element, m_BaseObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reads in the root element <sprites></sprites> (the DOMElement).
|
||||
// Input:
|
||||
// pElement The Xerces C++ Parser object that represents
|
||||
// the <sprites>.
|
||||
//-------------------------------------------------------------------
|
||||
void CGUI::Xerces_ReadRootSprites(XERCES_CPP_NAMESPACE::DOMElement *pElement)
|
||||
{
|
||||
// Iterate main children
|
||||
// they should all be <sprite> elements
|
||||
DOMNodeList *children = pElement->getChildNodes();
|
||||
|
||||
for (int i=0; i<children->getLength(); ++i)
|
||||
{
|
||||
DOMNode *child = children->item(i);
|
||||
|
||||
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
|
||||
{
|
||||
// Read in this whole object into the GUI
|
||||
DOMElement *element = (DOMElement*)child;
|
||||
Xerces_ReadSprite(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Notice! Recursive function!
|
||||
//
|
||||
// Reads in an <object></object> (the DOMElement) and stores it
|
||||
// as a child in the pParent.
|
||||
// It will also check the object's children and call this function
|
||||
// on them too. Also it will call all other functions that reads
|
||||
// in other stuff that can be found within an object. Such as
|
||||
// <action> will call Xerces_ReadAction (TODO, real funcion?)
|
||||
// Input:
|
||||
// pParent Parent to add this object as child in
|
||||
// pElement The Xerces C++ Parser object that represents
|
||||
// the <object>.
|
||||
//-------------------------------------------------------------------
|
||||
void CGUI::Xerces_ReadObject(DOMElement *pElement, CGUIObject *pParent)
|
||||
{
|
||||
assert(pParent && pElement);
|
||||
|
||||
// Our object we are going to create
|
||||
CGUIObject *object = NULL;
|
||||
|
||||
// Well first of all we need to determine the type
|
||||
string type = XMLString::transcode( pElement->getAttribute( XMLString::transcode("type") ) );
|
||||
|
||||
// Construct object from specified type
|
||||
// henceforth, we need to do a rollback before aborting.
|
||||
// i.e. releasing this object
|
||||
object = ConstructObject(type);
|
||||
|
||||
if (!object)
|
||||
{
|
||||
// Report error that object was unsuccessfully loaded
|
||||
ReportParseError("Unrecognized type: " + type);
|
||||
|
||||
delete object;
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Read Attributes
|
||||
//
|
||||
|
||||
bool NameSet = false;
|
||||
|
||||
// Now we can iterate all attributes and store
|
||||
DOMNamedNodeMap *attributes = pElement->getAttributes();
|
||||
for (int i=0; i<attributes->getLength(); ++i)
|
||||
{
|
||||
DOMAttr *attr = (DOMAttr*)attributes->item(i);
|
||||
string attr_name = XMLString::transcode( attr->getName() );
|
||||
string attr_value = XMLString::transcode( attr->getValue() );
|
||||
|
||||
// Ignore "type", we've already checked it
|
||||
if (attr_name == "type")
|
||||
continue;
|
||||
|
||||
// Also the name needs some special attention
|
||||
if (attr_name == "name")
|
||||
{
|
||||
object->SetName(attr_value);
|
||||
NameSet = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try setting the value
|
||||
try
|
||||
{
|
||||
object->SetSetting(attr_name, attr_value);
|
||||
}
|
||||
catch (PS_RESULT e)
|
||||
{
|
||||
ReportParseError("Can't set \"" + attr_name + "\" to \"" + attr_value + "\"");
|
||||
|
||||
// This is not a fatal error
|
||||
}
|
||||
}
|
||||
|
||||
// Check if name isn't set, report error in that case
|
||||
if (!NameSet)
|
||||
{
|
||||
// Set Random name! TODO
|
||||
}
|
||||
|
||||
//
|
||||
// Read Children
|
||||
//
|
||||
|
||||
// Iterate children
|
||||
DOMNodeList *children = pElement->getChildNodes();
|
||||
|
||||
for (int i=0; i<children->getLength(); ++i)
|
||||
{
|
||||
// Get node
|
||||
DOMNode *child = children->item(i);
|
||||
|
||||
// Check type (it's probably text or element)
|
||||
|
||||
// A child element
|
||||
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
|
||||
{
|
||||
// Check what name the elements got
|
||||
string element_name = XMLString::transcode( child->getNodeName() );
|
||||
|
||||
if (element_name == "object")
|
||||
{
|
||||
// First get element and not node
|
||||
DOMElement *element = (DOMElement*)child;
|
||||
|
||||
// TODO REPORT ERROR
|
||||
|
||||
// Call this function on the child
|
||||
Xerces_ReadObject(element, object);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (child->getNodeType() == DOMNode::TEXT_NODE)
|
||||
{
|
||||
CStr caption = XMLString::transcode( child->getNodeValue() );
|
||||
|
||||
// Text is only okay if it's the first element i.e. <object>caption ... </object>
|
||||
if (i==0)
|
||||
{
|
||||
// TODO !!!!! CROP STRING!
|
||||
|
||||
// Set the setting caption to this
|
||||
GUI<CStr>::SetSetting(object, "caption", caption);
|
||||
}
|
||||
// TODO check invalid strings?
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Input Child
|
||||
//
|
||||
|
||||
try
|
||||
{
|
||||
if (pParent == m_BaseObject)
|
||||
AddObject(object);
|
||||
else
|
||||
pParent->AddChild(object);
|
||||
}
|
||||
catch (PS_RESULT e)
|
||||
{
|
||||
ReportParseError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reads in a <sprite></sprite> (the DOMElement).
|
||||
// Input:
|
||||
// pElement The Xerces C++ Parser object that represents
|
||||
// the <sprite>.
|
||||
//-------------------------------------------------------------------
|
||||
void CGUI::Xerces_ReadSprite(XERCES_CPP_NAMESPACE::DOMElement *pElement)
|
||||
{
|
||||
assert(pElement);
|
||||
|
||||
// Sprite object we're adding
|
||||
CGUISprite sprite;
|
||||
|
||||
// and what will be its reference name
|
||||
CStr name;
|
||||
|
||||
//
|
||||
// Read Attributes
|
||||
//
|
||||
|
||||
// Get name, we know it exists because of DTD requirements
|
||||
name = XMLString::transcode( pElement->getAttribute( XMLString::transcode("name") ) );
|
||||
|
||||
//
|
||||
// Read Children (the images)
|
||||
//
|
||||
|
||||
// Iterate children
|
||||
DOMNodeList *children = pElement->getChildNodes();
|
||||
|
||||
for (int i=0; i<children->getLength(); ++i)
|
||||
{
|
||||
// Get node
|
||||
DOMNode *child = children->item(i);
|
||||
|
||||
// Check type (it's probably text or element)
|
||||
|
||||
// A child element
|
||||
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
|
||||
{
|
||||
// All Elements will be of type "image" by DTD law
|
||||
|
||||
// First get element and not node
|
||||
DOMElement *element = (DOMElement*)child;
|
||||
|
||||
// Call this function on the child
|
||||
Xerces_ReadImage(element, sprite);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Add Sprite
|
||||
//
|
||||
|
||||
m_Sprites[name] = sprite;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reads in a <image></image> (the DOMElement) to parent
|
||||
// Input:
|
||||
// parent Sprite to add this image too
|
||||
// pElement The Xerces C++ Parser object that represents
|
||||
// the <image>.
|
||||
//-------------------------------------------------------------------
|
||||
void CGUI::Xerces_ReadImage(XERCES_CPP_NAMESPACE::DOMElement *pElement, CGUISprite &parent)
|
||||
{
|
||||
assert(pElement);
|
||||
|
||||
// Image object we're adding
|
||||
SGUIImage image;
|
||||
|
||||
// TODO - Setup defaults here (or maybe they are in the SGUIImage ctor)
|
||||
|
||||
//
|
||||
// Read Attributes
|
||||
//
|
||||
|
||||
// Now we can iterate all attributes and store
|
||||
/* DOMNamedNodeMap *attributes = pElement->getAttributes();
|
||||
for (int i=0; i<attributes->getLength(); ++i)
|
||||
{
|
||||
DOMAttr *attr = (DOMAttr*)attributes->item(i);
|
||||
string attr_name = XMLString::transcode( attr->getName() );
|
||||
string attr_value = XMLString::transcode( attr->getValue() );
|
||||
|
||||
// This is the only attribute we want
|
||||
if (attr_name == "texture")
|
||||
{
|
||||
image.m_Texture = attr_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Log
|
||||
g_console.submit("echo Error attribute " + attr_name + " is not expected in <image>");
|
||||
return;
|
||||
}
|
||||
}
|
||||
*/
|
||||
//
|
||||
// Input
|
||||
//
|
||||
|
||||
parent.AddImage(image);
|
||||
}
|
197
source/gui/CGUI.h
Executable file
197
source/gui/CGUI.h
Executable file
@ -0,0 +1,197 @@
|
||||
/*
|
||||
CGUI
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
|
||||
--Overview--
|
||||
|
||||
This is the top class of the whole GUI, all objects
|
||||
and settings are stored within this class.
|
||||
|
||||
--More info--
|
||||
|
||||
Check GUI.h
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CGUI_H
|
||||
#define CGUI_H
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Includes / Compiler directives
|
||||
//--------------------------------------------------------
|
||||
#include "GUI.h"
|
||||
#include <xercesc/dom/DOM.hpp>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
#include <xercesc/util/PlatformUtils.hpp>
|
||||
|
||||
#include "input.h" // JW: grr, classes suck in this case :P
|
||||
|
||||
class XERCES_CPP_NAMESPACE::DOMElement;
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Macros
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Types
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Error declarations
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Declarations
|
||||
//--------------------------------------------------------
|
||||
|
||||
class CGUI
|
||||
{
|
||||
|
||||
// Only CGUIObject's leaf functions uses CGUI
|
||||
// freely.
|
||||
friend class CGUIObject;
|
||||
|
||||
private:
|
||||
// Private typedefs
|
||||
typedef CGUIObject *(*ConstructObjectFunction)();
|
||||
|
||||
public:
|
||||
CGUI();
|
||||
~CGUI();
|
||||
|
||||
// Initialize
|
||||
void Initialize(/*/*nemInput *pInput*/);
|
||||
|
||||
// Process
|
||||
void Process();
|
||||
|
||||
// Draw
|
||||
void Draw();
|
||||
|
||||
// Shutdown
|
||||
void Destroy();
|
||||
|
||||
// Load a GUI XML file
|
||||
void LoadXMLFile(const CStr &Filename);
|
||||
|
||||
// Checks if object exists and return true or false accordingly
|
||||
bool ObjectExists(const CStr &Name) const;
|
||||
|
||||
// Get pInput
|
||||
/// CInput *GetInput() { return m_pInput; }
|
||||
|
||||
// to add a type:
|
||||
// AddObjecType("button", &CButton::ConstructObject);
|
||||
void AddObjectType(const CStr &str, ConstructObjectFunction pFunc) { m_ObjectTypes[str] = pFunc; }
|
||||
|
||||
private:
|
||||
void UpdateObjects();
|
||||
|
||||
// Adds an object to the GUI's object database
|
||||
// Private, you can only add objects through XML files.
|
||||
void AddObject(CGUIObject* pObject);
|
||||
|
||||
// Report a XML parsing error
|
||||
void ReportParseError(const CStr &str, ...);
|
||||
|
||||
// Construct an object
|
||||
CGUIObject *ConstructObject(const CStr &str);
|
||||
|
||||
//
|
||||
// XML Reading Xerces C++ specific subroutines
|
||||
//
|
||||
|
||||
/**
|
||||
Xerces_* functions tree
|
||||
|
||||
==========================
|
||||
|
||||
<objects> (ReadRootObjects)
|
||||
|
|
||||
+-<object> (ReadObject)
|
||||
|
|
||||
+-<action>
|
||||
|
|
||||
+-Optional Type Extensions (CGUIObject::ReadExtendedElement) TODO
|
||||
|
|
||||
+-«object» *recursive*
|
||||
|
||||
|
||||
<styles> (ReadRootStyles)
|
||||
|
|
||||
+-<style> (ReadStyle)
|
||||
|
||||
|
||||
<sprites> (ReadRootSprites)
|
||||
|
|
||||
+-<sprite> (ReadSprite)
|
||||
|
|
||||
+-<image> (ReadImage)
|
||||
|
||||
|
||||
<setup> (ReadRootSetup)
|
||||
|
|
||||
+-<tooltip> (ReadToolTip)
|
||||
|
|
||||
+-<scrollbar> (ReadScrollBar)
|
||||
|
|
||||
+-<icon> (ReadIcon)
|
||||
|
||||
==========================
|
||||
*/
|
||||
|
||||
// These does not throw!
|
||||
// Because when reading in XML files, it won't be fatal
|
||||
// if an error occurs, perhaps one particular object
|
||||
// fails, but it'll still continue reading in the next
|
||||
// All Error are reported with ReportParseError
|
||||
|
||||
// Read roots
|
||||
void Xerces_ReadRootObjects(XERCES_CPP_NAMESPACE::DOMElement *pElement);
|
||||
void Xerces_ReadRootSprites(XERCES_CPP_NAMESPACE::DOMElement *pElement);
|
||||
|
||||
// Read subs
|
||||
void Xerces_ReadObject(XERCES_CPP_NAMESPACE::DOMElement *, CGUIObject *pParent);
|
||||
void Xerces_ReadSprite(XERCES_CPP_NAMESPACE::DOMElement *);
|
||||
void Xerces_ReadImage(XERCES_CPP_NAMESPACE::DOMElement *, CGUISprite &parent);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Variables
|
||||
|
||||
// Pointer to input module
|
||||
/// CInput *m_pInput;
|
||||
|
||||
//
|
||||
// Objects
|
||||
//
|
||||
|
||||
// Base Object, all its children are considered parentless
|
||||
// because this is no real object per se.
|
||||
CGUIObject* m_BaseObject;
|
||||
|
||||
// Just pointers for fast name access, each object
|
||||
// is really constructed within its parent for easy
|
||||
// recursive management.
|
||||
// Notice m_BaseObject won't belong here since it's
|
||||
// not considered a real object.
|
||||
map_pObjects m_pAllObjects;
|
||||
|
||||
// Function pointers to functions that constructs
|
||||
// CGUIObjects by name... For instance m_ObjectTypes["button"]
|
||||
// is filled with a function that will "return new CButton();"
|
||||
std::map<CStr, ConstructObjectFunction> m_ObjectTypes;
|
||||
|
||||
// Used when reading in XML files
|
||||
int m_Errors;
|
||||
|
||||
//
|
||||
// Sprites
|
||||
//
|
||||
|
||||
std::map<CStr, CGUISprite> m_Sprites;
|
||||
};
|
||||
|
||||
#endif
|
65
source/gui/CGUIButtonBehavior.cpp
Executable file
65
source/gui/CGUIButtonBehavior.cpp
Executable file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
CGUIButtonBehavior
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
*/
|
||||
|
||||
//#include "stdafx."
|
||||
#include "GUI.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Constructor / Destructor
|
||||
//-------------------------------------------------------------------
|
||||
CGUIButtonBehavior::CGUIButtonBehavior() : m_Pressed(false)
|
||||
{
|
||||
}
|
||||
|
||||
CGUIButtonBehavior::~CGUIButtonBehavior()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Handles messages send from the CGUI
|
||||
// Input:
|
||||
// Message Message ID, GUIM_*
|
||||
//-------------------------------------------------------------------
|
||||
void CGUIButtonBehavior::HandleMessage(const EGUIMessage &Message)
|
||||
{
|
||||
switch (Message)
|
||||
{
|
||||
case GUIM_POSTPROCESS:
|
||||
// Check if button has been pressed
|
||||
if (m_Pressed)
|
||||
{
|
||||
// Now check if mouse is released, that means
|
||||
// it's released outside, since GUIM_MOUSE_RELEASE_LEFT
|
||||
// would've handled m_Pressed and reset it already
|
||||
|
||||
// Get input structure
|
||||
/// if (GetGUI()->GetInput()->mRelease(NEMM_BUTTON1))
|
||||
{
|
||||
// Reset
|
||||
m_Pressed = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GUIM_MOUSE_PRESS_LEFT:
|
||||
m_Pressed = true;
|
||||
break;
|
||||
|
||||
case GUIM_MOUSE_RELEASE_LEFT:
|
||||
if (m_Pressed)
|
||||
{
|
||||
m_Pressed = false;
|
||||
// BUTTON WAS CLICKED
|
||||
HandleMessage(GUIM_PRESSED);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
59
source/gui/CGUIButtonBehavior.h
Executable file
59
source/gui/CGUIButtonBehavior.h
Executable file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
GUI Object - Button
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
|
||||
--Overview--
|
||||
|
||||
Interface class that enhance the CGUIObject with
|
||||
buttony behavior (click and release to click a button),
|
||||
and the GUI message GUIM_PRESSED.
|
||||
When creating a class with extended settings and
|
||||
buttony behavior, just do a multiple inheritance.
|
||||
|
||||
--More info--
|
||||
|
||||
Check GUI.h
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CGUIButtonBehavior_H
|
||||
#define CGUIButtonBehavior_H
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Includes / Compiler directives
|
||||
//--------------------------------------------------------
|
||||
#include "GUI.h"
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Macros
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Types
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Declarations
|
||||
//--------------------------------------------------------
|
||||
|
||||
// Abstract Data Type
|
||||
class CGUIButtonBehavior : virtual public CGUIObject
|
||||
{
|
||||
public:
|
||||
CGUIButtonBehavior();
|
||||
virtual ~CGUIButtonBehavior();
|
||||
|
||||
// Handle Messages
|
||||
virtual void HandleMessage(const EGUIMessage &Message);
|
||||
|
||||
protected:
|
||||
// Everybody knows how a button works, you don't simply press it,
|
||||
// you have to first press the button, and then release it...
|
||||
// in between those two steps you can actually leave the button
|
||||
// area, as long as you release it within the button area... Anyway
|
||||
// this lets us know we are done with step one (clicking).
|
||||
bool m_Pressed;
|
||||
};
|
||||
|
||||
#endif
|
407
source/gui/CGUIObject.cpp
Executable file
407
source/gui/CGUIObject.cpp
Executable file
@ -0,0 +1,407 @@
|
||||
/*
|
||||
CGUIObject
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
*/
|
||||
|
||||
//#include "stdafx."
|
||||
#include "GUI.h"
|
||||
///#include "Parser/parser.h"
|
||||
#include <assert.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Offsets
|
||||
map_Settings CGUIObject::m_SettingsInfo;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Implementation Macros
|
||||
//-------------------------------------------------------------------
|
||||
#define _GUI_ADD_OFFSET(type, str, var) \
|
||||
SettingsInfo[str].m_Offset = offsetof(CGUIObject, m_BaseSettings) + offsetof(SGUIBaseSettings,var); \
|
||||
SettingsInfo[str].m_Type = type;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Constructor / Destructor
|
||||
//-------------------------------------------------------------------
|
||||
CGUIObject::CGUIObject() :
|
||||
m_pGUI(NULL),
|
||||
m_pParent(NULL),
|
||||
m_MouseHovering(false)
|
||||
{
|
||||
// Default values of base settings !
|
||||
m_BaseSettings.m_Enabled = true;
|
||||
m_BaseSettings.m_Hidden = false;
|
||||
m_BaseSettings.m_Style = "null";
|
||||
m_BaseSettings.m_Z = 0.f;
|
||||
|
||||
// Static! Only done once
|
||||
if (m_SettingsInfo.empty())
|
||||
{
|
||||
SetupBaseSettingsInfo(m_SettingsInfo);
|
||||
}
|
||||
}
|
||||
|
||||
CGUIObject::~CGUIObject()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Change the base settings
|
||||
// Input:
|
||||
// Set Setting struct
|
||||
//-------------------------------------------------------------------
|
||||
void CGUIObject::SetBaseSettings(const SGUIBaseSettings &Set)
|
||||
{
|
||||
m_BaseSettings = Set;
|
||||
CheckSettingsValidity();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Adds a child
|
||||
// Notice nothing will be returned or thrown if the child hasn't
|
||||
// been inputted into the GUI yet. This is because that's were
|
||||
// all is checked. Now we're just linking two objects, but
|
||||
// it's when we're inputting them into the GUI we'll check
|
||||
// validity! Notice also when adding it to the GUI this function
|
||||
// will inevitably have been called by CGUI::AddObject which
|
||||
// will catch the throw and return the error code.
|
||||
// i.e. The user will never put in the situation wherein a throw
|
||||
// must be caught, the GUI's internal error handling will be
|
||||
// completely transparent to the interfacially sequential model.
|
||||
// Input:
|
||||
// pChild Child to add
|
||||
//-------------------------------------------------------------------
|
||||
void CGUIObject::AddChild(CGUIObject *pChild)
|
||||
{
|
||||
//
|
||||
// assert(pChild);
|
||||
|
||||
pChild->SetParent(this);
|
||||
|
||||
m_Children.push_back(pChild);
|
||||
|
||||
// If this (not the child) object is already attached
|
||||
// to a CGUI, it pGUI pointer will be non-null.
|
||||
// This will mean we'll have to check if we're using
|
||||
// names already used.
|
||||
if (pChild->GetGUI())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Atomic function, if it fails it won't
|
||||
// have changed anything
|
||||
//UpdateObjects();
|
||||
pChild->GetGUI()->UpdateObjects();
|
||||
}
|
||||
catch (PS_RESULT e)
|
||||
{
|
||||
// If anything went wrong, reverse what we did and throw
|
||||
// an exception telling it never added a child
|
||||
m_Children.erase( m_Children.end()-1 );
|
||||
|
||||
// We'll throw the same exception for easier
|
||||
// error handling
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
// else do nothing
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Adds object and its children to the map, it's name being the
|
||||
// first part, and the second being itself.
|
||||
// Input:
|
||||
// ObjectMap Checks to see if the name's already taken
|
||||
// Output:
|
||||
// ObjectMap Fills it with more
|
||||
// Throws:
|
||||
// PS_NAME_AMBIGUITY
|
||||
//-------------------------------------------------------------------
|
||||
void CGUIObject::AddToPointersMap(map_pObjects &ObjectMap)
|
||||
{
|
||||
// Just don't do anything about the top node
|
||||
if (m_pParent == NULL)
|
||||
return;
|
||||
|
||||
// Now actually add this one
|
||||
// notice we won't add it if it's doesn't have any parent
|
||||
// (i.e. being the base object)
|
||||
if (m_Name == string())
|
||||
{
|
||||
throw PS_NEEDS_NAME;
|
||||
}
|
||||
if (ObjectMap.count(m_Name) > 0)
|
||||
{
|
||||
throw PS_NAME_AMBIGUITY;
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectMap[m_Name] = this;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Destroys all children and the current object too
|
||||
//-------------------------------------------------------------------
|
||||
void CGUIObject::Destroy()
|
||||
{
|
||||
// Is there anything besides the children to destroy?
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Sets up a map_size_t to include the variables in m_BaseSettings
|
||||
// Input:
|
||||
// p Pointers that should be filled with base
|
||||
// variables
|
||||
//-------------------------------------------------------------------
|
||||
void CGUIObject::SetupBaseSettingsInfo(map_Settings &SettingsInfo)
|
||||
{
|
||||
_GUI_ADD_OFFSET("bool", "enabled", m_Enabled)
|
||||
_GUI_ADD_OFFSET("bool", "hidden", m_Hidden)
|
||||
_GUI_ADD_OFFSET("rect", "size1024", m_Size)
|
||||
_GUI_ADD_OFFSET("string", "style", m_Style)
|
||||
_GUI_ADD_OFFSET("float", "z", m_Z)
|
||||
_GUI_ADD_OFFSET("string", "caption", m_Caption)
|
||||
}
|
||||
|
||||
|
||||
extern int gui_mouse_x, gui_mouse_y; // declared in cgui.cpp
|
||||
// JW: how about MouseOver(mouse_x, mouse_y) instead of accessing the global mouse pos?
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Checks if mouse is over and returns result
|
||||
// Input:
|
||||
// x, y Absolute mouse position
|
||||
//-------------------------------------------------------------------
|
||||
bool CGUIObject::MouseOver()
|
||||
{
|
||||
if (!GetGUI())
|
||||
throw PS_NEEDS_PGUI;
|
||||
|
||||
return (gui_mouse_x >= m_BaseSettings.m_Size.left &&
|
||||
gui_mouse_x <= m_BaseSettings.m_Size.right &&
|
||||
gui_mouse_y >= m_BaseSettings.m_Size.bottom &&
|
||||
gui_mouse_y <= m_BaseSettings.m_Size.top);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Inputes the object that is currently hovered, this function
|
||||
// updates this object accordingly (i.e. if it's the object
|
||||
// being inputted one thing happens, and not, another).
|
||||
// Input:
|
||||
// pMouseOver Object that is currently hovered
|
||||
// can OF COURSE be NULL too!
|
||||
//-------------------------------------------------------------------
|
||||
void CGUIObject::UpdateMouseOver(CGUIObject * const &pMouseOver)
|
||||
{
|
||||
// Check if this is the object being hovered.
|
||||
if (pMouseOver == this)
|
||||
{
|
||||
if (!m_MouseHovering)
|
||||
{
|
||||
// It wasn't hovering, so that must mean it just entered
|
||||
HandleMessage(GUIM_MOUSE_ENTER);
|
||||
}
|
||||
|
||||
// Either way, set to true
|
||||
m_MouseHovering = true;
|
||||
|
||||
// call mouse over
|
||||
HandleMessage(GUIM_MOUSE_OVER);
|
||||
}
|
||||
else // Some other object (or none) is hovered
|
||||
{
|
||||
if (m_MouseHovering)
|
||||
{
|
||||
m_MouseHovering = false;
|
||||
HandleMessage(GUIM_MOUSE_LEAVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Check if setting exists by name
|
||||
// Input:
|
||||
// Setting Setting by name
|
||||
//-------------------------------------------------------------------
|
||||
bool CGUIObject::SettingExists(const CStr &Setting) const
|
||||
{
|
||||
// Because GetOffsets will direct dynamically defined
|
||||
// classes with polymorifsm to respective m_SettingsInfo
|
||||
// we need to make no further updates on this function
|
||||
// in derived classes.
|
||||
return (GetSettingsInfo().count(Setting) == 1)?true:false;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Set a setting by string, regardless of what type it is...
|
||||
// example a CRect(10,10,20,20) would be "10 10 20 20"
|
||||
// Input:
|
||||
// Setting Setting by name
|
||||
// Value Value
|
||||
//-------------------------------------------------------------------
|
||||
void CGUIObject::SetSetting(const CStr &Setting, const CStr &Value)
|
||||
{
|
||||
if (!SettingExists(Setting))
|
||||
{
|
||||
throw PS_FAIL;
|
||||
}
|
||||
|
||||
// Get setting
|
||||
SGUISetting set = GetSettingsInfo()[Setting];
|
||||
|
||||
if (set.m_Type == "string")
|
||||
{
|
||||
GUI<string>::SetSetting(this, Setting, Value);
|
||||
}
|
||||
else
|
||||
if (set.m_Type == "float")
|
||||
{
|
||||
// Use the parser to parse the values
|
||||
/* CParser parser;
|
||||
parser.InputTaskType("", "_$value_");
|
||||
|
||||
CParserLine line;
|
||||
line.ParseString(parser, Value);
|
||||
if (!line.m_ParseOK)
|
||||
{
|
||||
// ERROR!
|
||||
throw PS_FAIL;
|
||||
}
|
||||
|
||||
float value;
|
||||
if (!line.GetArgFloat(0, value))
|
||||
{
|
||||
// ERROR!
|
||||
throw PS_FAIL;
|
||||
}
|
||||
|
||||
// Finally the rectangle values
|
||||
GUI<float>::SetSetting(this, Setting, value);
|
||||
*/
|
||||
GUI<float>::SetSetting(this, Setting, (float)atof(Value.c_str()) );
|
||||
}
|
||||
else
|
||||
if (set.m_Type == "rect")
|
||||
{
|
||||
// TEMP
|
||||
GUI<CRect>::SetSetting(this, Setting, CRect(100,100,200,200));
|
||||
|
||||
// Use the parser to parse the values
|
||||
/* CParser parser;
|
||||
parser.InputTaskType("", "_$value_$value_$value_$value_");
|
||||
|
||||
CParserLine line;
|
||||
line.ParseString(parser, Value);
|
||||
if (!line.m_ParseOK)
|
||||
{
|
||||
// ERROR!
|
||||
throw PS_FAIL;
|
||||
}
|
||||
int values[4];
|
||||
for (int i=0; i<4; ++i)
|
||||
{
|
||||
if (!line.GetArgInt(i, values[i]))
|
||||
{
|
||||
// ERROR!
|
||||
throw PS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally the rectangle values
|
||||
CRect rect(values[0], values[1], values[2], values[3]);
|
||||
GUI<CRect>::SetSetting(this, Setting, rect);
|
||||
*/ }
|
||||
else
|
||||
{
|
||||
throw PS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Inputs a reference pointer, checks if the new inputted object
|
||||
// if hovered, if so, then check if (this)'s Z value is greater
|
||||
// than the inputted object... If so then the object is closer
|
||||
// and we'll replace the pointer with (this)
|
||||
// Also Notice input can be NULL, which means the Z value demand
|
||||
// is out. NOTICE you can't input NULL as const so you'll have
|
||||
// to set an object to NULL.
|
||||
// Input:
|
||||
// pObject Object pointer
|
||||
// Input:
|
||||
// pObject Object pointer, either old or (this)
|
||||
//-------------------------------------------------------------------
|
||||
void CGUIObject::ChooseMouseOverAndClosest(CGUIObject* &pObject)
|
||||
{
|
||||
if (MouseOver())
|
||||
{
|
||||
// Check if we've got competition at all
|
||||
if (pObject == NULL)
|
||||
{
|
||||
pObject = this;
|
||||
return;
|
||||
}
|
||||
|
||||
// Or if it's closer
|
||||
if (GetBaseSettings().m_Z >= pObject->GetBaseSettings().m_Z)
|
||||
{
|
||||
pObject = this;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Object's parent, notice that if the parent is the top-node
|
||||
// then, we'll return NULL, because we don't want the top-node
|
||||
// taken into account.
|
||||
// Return:
|
||||
// The Parent
|
||||
//-------------------------------------------------------------------
|
||||
CGUIObject *CGUIObject::GetParent()
|
||||
{
|
||||
// Important, we're not using GetParent() for these
|
||||
// checks, that could screw it up
|
||||
if (m_pParent)
|
||||
{
|
||||
if (m_pParent->m_pParent == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_pParent;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Called every time settings are change, this is where you check
|
||||
// validity (not syntactical, that's already check) of your values.
|
||||
// perhaps you can't have Z being below 0. Anyway this is where
|
||||
// all is checked, and if you wanbt to add more in a derived object
|
||||
// do that in GUIM_SETTINGS_UPDATED
|
||||
//-------------------------------------------------------------------
|
||||
void CGUIObject::CheckSettingsValidity()
|
||||
{
|
||||
// If we hide an object, reset many of its parts
|
||||
if (GetBaseSettings().m_Hidden)
|
||||
{
|
||||
// Simulate that no object is hovered for this object and all its children
|
||||
// why? because it's
|
||||
try
|
||||
{
|
||||
GUI<CGUIObject*>::RecurseObject(0, this, &CGUIObject::UpdateMouseOver, NULL);
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Send message to myself
|
||||
HandleMessage(GUIM_SETTINGS_UPDATED);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
278
source/gui/CGUIObject.h
Executable file
278
source/gui/CGUIObject.h
Executable file
@ -0,0 +1,278 @@
|
||||
/*
|
||||
The base class of an object
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
|
||||
--Overview--
|
||||
|
||||
All objects are derived from this class, it's an ADT
|
||||
so it can't be used per se
|
||||
|
||||
--Usage--
|
||||
|
||||
Write about how to use it here
|
||||
|
||||
--Examples--
|
||||
|
||||
Provide examples of how to use this code, if necessary
|
||||
|
||||
--More info--
|
||||
|
||||
Check GUI.h
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CGUIObject_H
|
||||
#define CGUIObject_H
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Includes / Compiler directives
|
||||
//--------------------------------------------------------
|
||||
#include "GUI.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct SGUISetting;
|
||||
class CGUI;
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Macros
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Types
|
||||
//--------------------------------------------------------
|
||||
|
||||
// Map with pointers
|
||||
typedef std::map<CStr, SGUISetting> map_Settings;
|
||||
typedef std::vector<CGUIObject*> vector_pObjects;
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Error declarations
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Declarations
|
||||
//--------------------------------------------------------
|
||||
|
||||
// TEMP
|
||||
struct CRect
|
||||
{
|
||||
CRect() {}
|
||||
CRect(int _l, int _b, int _r, int _t) :
|
||||
top(_t),
|
||||
bottom(_b),
|
||||
right(_r),
|
||||
left(_l) {}
|
||||
int bottom, top, left, right;
|
||||
|
||||
bool operator ==(const CRect &rect) const
|
||||
{
|
||||
return (bottom==rect.bottom) &&
|
||||
(top==rect.top) &&
|
||||
(left==rect.left) &&
|
||||
(right==rect.right);
|
||||
}
|
||||
|
||||
bool operator !=(const CRect &rect) const
|
||||
{
|
||||
return !(*this==rect);
|
||||
}
|
||||
};
|
||||
|
||||
// TEMP
|
||||
struct CColor
|
||||
{
|
||||
float r, g, b, a;
|
||||
};
|
||||
|
||||
// Text alignments
|
||||
enum EAlign { EAlign_Left, EAlign_Right, EAlign_Center };
|
||||
enum EValign { EValign_Top, EValign_Bottom, EValign_Center };
|
||||
|
||||
// Stores the information where to find a variable
|
||||
// in a GUI-Object object, also what type it is
|
||||
struct SGUISetting
|
||||
{
|
||||
size_t m_Offset; // The offset from CGUIObject to the variable (not from SGUIBaseSettings or similar)
|
||||
CStr m_Type; // "string" or maybe "int"
|
||||
};
|
||||
|
||||
// Base settings, all objects possess these settings
|
||||
// in their m_BaseSettings
|
||||
// Instructions can be found in the documentations
|
||||
struct SGUIBaseSettings
|
||||
{
|
||||
bool m_Hidden;
|
||||
bool m_Enabled;
|
||||
bool m_Absolute;
|
||||
CRect m_Size;
|
||||
CStr m_Style;
|
||||
float m_Z;
|
||||
CStr m_Caption; // Is usually set within an XML element and not in the attributes
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
// GUI object such as a button or an input-box.
|
||||
// Abstract data type !
|
||||
class CGUIObject
|
||||
{
|
||||
friend class CGUI;
|
||||
friend class GUI;
|
||||
|
||||
public:
|
||||
CGUIObject();
|
||||
virtual ~CGUIObject();
|
||||
|
||||
// Get Offsets
|
||||
virtual map_Settings GetSettingsInfo() const { return m_SettingsInfo; }
|
||||
|
||||
// Is mouse over
|
||||
// because it's virtual you can change the
|
||||
// mouse over demands, such as making a round
|
||||
// button, or just modifying it when changed,
|
||||
// like for a combo box.
|
||||
// The default one uses m_Size
|
||||
virtual bool MouseOver();
|
||||
|
||||
//
|
||||
// Leaf Functions
|
||||
//
|
||||
|
||||
// Get/Set
|
||||
// Name
|
||||
std::string GetName() const { return m_Name; }
|
||||
void SetName(const std::string &Name) { m_Name = Name; }
|
||||
|
||||
// Fill a map_pObjects with this object (does not include recursion)
|
||||
void AddToPointersMap(map_pObjects &ObjectMap);
|
||||
|
||||
// Add child
|
||||
void AddChild(CGUIObject *pChild);
|
||||
|
||||
//
|
||||
// Iterate
|
||||
//
|
||||
|
||||
vector_pObjects::iterator ChildrenItBegin() { return m_Children.begin(); }
|
||||
vector_pObjects::iterator ChildrenItEnd() { return m_Children.end(); }
|
||||
|
||||
//
|
||||
// Settings Management
|
||||
//
|
||||
|
||||
SGUIBaseSettings GetBaseSettings() const { return m_BaseSettings; }
|
||||
void SetBaseSettings(const SGUIBaseSettings &Set);
|
||||
|
||||
// Checks if settings exists, only available for derived
|
||||
// classes that has this set up, that's why the base
|
||||
// class just returns false
|
||||
bool SettingExists(const CStr &Setting) const;
|
||||
|
||||
// Setup base pointers
|
||||
void SetupBaseSettingsInfo(map_Settings &SettingsInfo);
|
||||
|
||||
// Set Setting by string
|
||||
void SetSetting(const CStr &Setting, const CStr &Value);
|
||||
|
||||
// Should be called every time the settings has been updated
|
||||
// will also send a message GUIM_SETTINGS_UPDATED, so that
|
||||
// if a derived object wants to add things to be updated,
|
||||
// they add it in that message part, this is a better solution
|
||||
// than making this virtual, since the updates that the base
|
||||
// class does, are the most essential.
|
||||
// This is not private since there should be no harm in
|
||||
// checking validity
|
||||
void CheckSettingsValidity();
|
||||
|
||||
protected:
|
||||
//
|
||||
// Methods that the CGUI will call using
|
||||
// its friendship, these should not
|
||||
// be called by user.
|
||||
//
|
||||
// These functions' security are alot
|
||||
// what constitutes the GUI's
|
||||
//
|
||||
|
||||
// Calls Destroy on all children, and deallocates all memory
|
||||
virtual void Destroy();
|
||||
|
||||
// Messages
|
||||
// This function is called with different messages
|
||||
// for instance when the mouse enters the object.
|
||||
virtual void HandleMessage(const EGUIMessage &Message)=0;
|
||||
|
||||
// Draw
|
||||
virtual void Draw()=0;
|
||||
|
||||
|
||||
// Setting and getting the GUI object can only be done
|
||||
// from within
|
||||
// SetGUI uses a first parameter that fits into RecurseObject
|
||||
CGUI *GetGUI() { return m_pGUI; }
|
||||
void SetGUI(CGUI * const &pGUI) { m_pGUI = pGUI; }
|
||||
|
||||
// Set parent
|
||||
void SetParent(CGUIObject *pParent) { m_pParent = pParent; }
|
||||
|
||||
// NOTE! This will not just return m_pParent, when that is need
|
||||
// use it! There is one exception to it, when the parent is
|
||||
// the top-node (the object that isn't a real object), this
|
||||
// will return NULL, so that the top-node's children are
|
||||
// seemingly parentless.
|
||||
CGUIObject *GetParent();
|
||||
|
||||
// Clear children, removes all children
|
||||
// Update objects, will basically use the this base class
|
||||
// to access a private member in CGUI, this base
|
||||
// class will be only one with permission
|
||||
// void UpdateObjects();
|
||||
|
||||
|
||||
private:
|
||||
// Functions used fully private and by friends (mainly the CGUI)
|
||||
|
||||
// You input pointer, and if the Z value of this object
|
||||
// is greater than the one inputted, the pointer is changed to this.
|
||||
void ChooseMouseOverAndClosest(CGUIObject* &pObject);
|
||||
|
||||
// Update Mouse Over (for this object only)
|
||||
void UpdateMouseOver(CGUIObject * const &pMouseOver);
|
||||
|
||||
|
||||
// Variables
|
||||
|
||||
protected:
|
||||
// Name of object
|
||||
CStr m_Name;
|
||||
|
||||
// Constructed on the heap, will be destroyed along with the the object
|
||||
vector_pObjects m_Children;
|
||||
|
||||
// Pointer to parent
|
||||
CGUIObject *m_pParent;
|
||||
|
||||
// Base settings
|
||||
SGUIBaseSettings m_BaseSettings;
|
||||
|
||||
// More variables
|
||||
|
||||
// Is mouse hovering the object? used with the function MouseOver()
|
||||
bool m_MouseHovering;
|
||||
|
||||
// Offset database
|
||||
// tells us where a variable by a string name is
|
||||
// located hardcoded, in order to acquire a pointer
|
||||
// for that variable... Say "frozen" gives
|
||||
// the offset from CGUIObject to m_Frozen
|
||||
// note! _NOT_ from SGUIBaseSettings to m_Frozen!
|
||||
static map_Settings m_SettingsInfo;
|
||||
|
||||
private:
|
||||
// An object can't function stand alone
|
||||
CGUI *m_pGUI;
|
||||
};
|
||||
|
||||
#endif
|
10
source/gui/CGUISettingsObject.cpp
Executable file
10
source/gui/CGUISettingsObject.cpp
Executable file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
CGUISettingsObject
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
*/
|
||||
|
||||
//#include "stdafx.h"
|
||||
#include "GUI.h"
|
||||
|
||||
using namespace std;
|
111
source/gui/CGUISettingsObject.h
Executable file
111
source/gui/CGUISettingsObject.h
Executable file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
Object with settings
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
|
||||
--Overview--
|
||||
|
||||
Generic object that stores a struct with settings
|
||||
|
||||
--Usage--
|
||||
|
||||
If an object wants settings with a standard,
|
||||
it will use this as a middle step instead of being
|
||||
directly derived from CGUIObject
|
||||
|
||||
--Examples--
|
||||
|
||||
instead of:
|
||||
|
||||
class CButton : public CGUIObject
|
||||
|
||||
you go:
|
||||
|
||||
class CButton : public CGUISettingsObject<SButtonSettings>
|
||||
|
||||
and SButtonSettings will be included as m_Settings with
|
||||
all gets and sets set up
|
||||
|
||||
--More info--
|
||||
|
||||
Check GUI.h
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CGUISettingsObject_H
|
||||
#define CGUISettingsObject_H
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Includes / Compiler directives
|
||||
//--------------------------------------------------------
|
||||
#include "GUI.h"
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Macros
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Types
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Error declarations
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Declarations
|
||||
//--------------------------------------------------------
|
||||
|
||||
// Generic object that stores a struct with settings
|
||||
|
||||
template <typename SETTINGS>
|
||||
class CGUISettingsObject : virtual public CGUIObject
|
||||
{
|
||||
public:
|
||||
CGUISettingsObject() {}
|
||||
virtual ~CGUISettingsObject() {}
|
||||
|
||||
// Get Offsets
|
||||
// important so it returns this m_Offsets and not CGUIObject::m_SettingsInfo
|
||||
virtual map_Settings GetSettingsInfo() const { return m_SettingsInfo; }
|
||||
|
||||
// GetSettings()
|
||||
// returns a copy of m_Settings
|
||||
SETTINGS GetSettings() const { return m_Settings; }
|
||||
|
||||
// SetSettings
|
||||
// Sets m_Settings to _set
|
||||
void SetSettings(const SETTINGS &Set)
|
||||
{
|
||||
m_Settings = Set;
|
||||
|
||||
//CheckSettingsValidity();
|
||||
// Since that function out-commented above really
|
||||
// does just update the base settings, we'll call
|
||||
// the message immediately instead
|
||||
try
|
||||
{
|
||||
HandleMessage(GUIM_SETTINGS_UPDATED);
|
||||
}
|
||||
catch (...) { }
|
||||
}
|
||||
|
||||
protected:
|
||||
// Settings
|
||||
SETTINGS m_Settings;
|
||||
|
||||
// Offset database
|
||||
// tells us where a variable by a string name is
|
||||
// located hardcoded, in order to acquire a pointer
|
||||
// for that variable... Say "frozen" gives
|
||||
// the offset from CGUIObject to m_Frozen
|
||||
// note! _NOT_ from SGUIBaseSettings to m_Frozen!
|
||||
//
|
||||
// Note that it's imperative that this m_SettingsInfo includes
|
||||
// all offsets of m_BaseSettings too, because when
|
||||
// using this class, this m_SettingsInfo will be the only
|
||||
// one used.
|
||||
static map_Settings m_SettingsInfo;
|
||||
};
|
||||
|
||||
#endif
|
42
source/gui/CGUISprite.cpp
Executable file
42
source/gui/CGUISprite.cpp
Executable file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
CGUISprite
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
*/
|
||||
|
||||
//#include "stdafx.h"
|
||||
#include "GUI.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Draw this sprite
|
||||
// Input:
|
||||
// rect Rectangle where the sprite should be drawn
|
||||
// z Same as above only with Z-value
|
||||
// clipping The clipping rectangle, things should only
|
||||
// be drawn within these perimeters.
|
||||
//-------------------------------------------------------------------
|
||||
void CGUISprite::Draw(const float &z, const CRect &rect, const CRect &clipping=CRect(0,0,0,0))
|
||||
{
|
||||
bool DoClipping = (clipping != CRect(0,0,0,0));
|
||||
|
||||
// Iterate all images and request them being drawn be the
|
||||
// CRenderer
|
||||
std::vector<SGUIImage>::iterator it;
|
||||
for (it=m_Images.begin(); it!=m_Images.end(); ++it)
|
||||
{
|
||||
glPushMatrix();
|
||||
glTranslatef(0.0f, 0.0f, z);
|
||||
|
||||
// Do this
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2i(rect.right, rect.bottom);
|
||||
glVertex2i(rect.left, rect.bottom);
|
||||
glVertex2i(rect.left, rect.top);
|
||||
glVertex2i(rect.right, rect.top);
|
||||
glEnd();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
80
source/gui/CGUISprite.h
Executable file
80
source/gui/CGUISprite.h
Executable file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
A GUI Sprite
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
|
||||
--Overview--
|
||||
|
||||
A GUI Sprite, which is actually a collage of several
|
||||
sprites.
|
||||
|
||||
--Usage--
|
||||
|
||||
Used internally and declared in XML files, read documentations
|
||||
on how.
|
||||
|
||||
--More info--
|
||||
|
||||
Check GUI.h
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CGUISprite_H
|
||||
#define CGUISprite_H
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Includes / Compiler directives
|
||||
//--------------------------------------------------------
|
||||
#include "GUI.h"
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Macros
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Types
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Error declarations
|
||||
//--------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Declarations
|
||||
//--------------------------------------------------------
|
||||
|
||||
// Actual sprite
|
||||
struct SGUIImage
|
||||
{
|
||||
CStr m_Texture;
|
||||
|
||||
// Placement modifiers
|
||||
int m_Pixel[4];
|
||||
float m_Percent[4];
|
||||
|
||||
// Texture modifiers
|
||||
int m_TexturePixel[4];
|
||||
float m_TexturePercent[4];
|
||||
|
||||
//CColor m_BackColor;
|
||||
//CColor m_BorderColor;
|
||||
int m_BorderSize;
|
||||
};
|
||||
|
||||
// The GUI sprite, is actually several real sprites (images).
|
||||
class CGUISprite
|
||||
{
|
||||
public:
|
||||
CGUISprite() {}
|
||||
virtual ~CGUISprite() {}
|
||||
|
||||
// Execute a drawing request for this sprite
|
||||
void Draw(const float &z, const CRect &rect, const CRect &clipping);
|
||||
|
||||
void AddImage(const SGUIImage &image) { m_Images.push_back(image); }
|
||||
|
||||
private:
|
||||
std::vector<SGUIImage> m_Images;
|
||||
};
|
||||
|
||||
#endif
|
27
source/gui/GUI.cpp
Executable file
27
source/gui/GUI.cpp
Executable file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
GUI
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
*/
|
||||
|
||||
//#include "stdafx.h"
|
||||
#include "GUI.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Error definitions
|
||||
//--------------------------------------------------------
|
||||
///DEFINE_ERROR(PS_FAIL, "fail")
|
||||
///DEFINE_ERROR(PS_OK, "ok")
|
||||
DEFINE_ERROR(PS_NAME_TAKEN, "Reference name is taken")
|
||||
DEFINE_ERROR(PS_OBJECT_FAIL, "Object provided is null")
|
||||
DEFINE_ERROR(PS_SETTING_FAIL, "Setting does not exist")
|
||||
DEFINE_ERROR(PS_VALUE_INVALID, "Value provided is syntactically incorrect")
|
||||
DEFINE_ERROR(PS_NEEDS_PGUI, "m_pGUI is NULL when needed for a requested operation")
|
||||
DEFINE_ERROR(PS_NAME_AMBIGUITY, "Two or more objects are sharing name")
|
||||
DEFINE_ERROR(PS_NEEDS_NAME, "An object are trying to fit into a GUI without a name")
|
||||
|
||||
DEFINE_ERROR(PS_LEXICAL_FAIL, "PS_LEXICAL_FAIL")
|
||||
DEFINE_ERROR(PS_SYNTACTICAL_FAIL, "PS_SYNTACTICAL_FAIL")
|
412
source/gui/GUI.h
Executable file
412
source/gui/GUI.h
Executable file
@ -0,0 +1,412 @@
|
||||
/*
|
||||
GUI Inclusion file
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
|
||||
--Overview--
|
||||
|
||||
Include this file and it will include the whole GUI
|
||||
|
||||
Also includes global GUI functions that is used to
|
||||
make global functions templated
|
||||
|
||||
--More info--
|
||||
|
||||
http://gee.pyro.nu/wfg/GUI/
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GUI_H
|
||||
#define GUI_H
|
||||
|
||||
#ifdef WIN32
|
||||
# pragma warning(disable:4786)
|
||||
#endif // WIN32
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Includes / Compiler directives
|
||||
//--------------------------------------------------------
|
||||
// { temp TODO
|
||||
/// #include "nemesis.h"
|
||||
#define DEFINE_ERROR(x, y) PS_RESULT x=y;
|
||||
#define DECLARE_ERROR(x) extern PS_RESULT x;
|
||||
// } temp
|
||||
|
||||
// Includes used by the whole GUI
|
||||
#include <map>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#include "ogl.h"
|
||||
|
||||
//--------------------------------------------------------
|
||||
// TODO name this section
|
||||
//--------------------------------------------------------
|
||||
class CGUIObject;
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Macros
|
||||
//--------------------------------------------------------
|
||||
// Temp
|
||||
///#define CInput nemInput
|
||||
#define CStr std::string
|
||||
|
||||
// Example
|
||||
// GUI_ADD_OFFSET(CButton, SButtonSettings, m_Settings, "frozen", m_Frozen);
|
||||
//
|
||||
#define GUI_ADD_OFFSET(_class, _struct, name, type, str, var) \
|
||||
m_SettingsInfo[str].m_Offset = offsetof(_class, name) + offsetof(_struct, var); \
|
||||
m_SettingsInfo[str].m_Type = type;
|
||||
|
||||
// Declares the static variable in CGUISettingsObject<>
|
||||
#define DECLARE_SETTINGS_INFO(_struct) \
|
||||
map_Settings CGUISettingsObject<_struct>::m_SettingsInfo;
|
||||
|
||||
// Setup an object's ConstructObject function
|
||||
#define GUI_OBJECT(obj) \
|
||||
public: \
|
||||
static CGUIObject *ConstructObject() { return new obj(); }
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Types
|
||||
//--------------------------------------------------------
|
||||
// Message send to HandleMessage in order
|
||||
// to give life to Objects manually with
|
||||
// a derived HandleMessage().
|
||||
enum EGUIMessage
|
||||
{
|
||||
GUIM_PREPROCESS,
|
||||
GUIM_POSTPROCESS,
|
||||
GUIM_MOUSE_OVER,
|
||||
GUIM_MOUSE_ENTER,
|
||||
GUIM_MOUSE_LEAVE,
|
||||
GUIM_MOUSE_PRESS_LEFT,
|
||||
GUIM_MOUSE_PRESS_RIGHT,
|
||||
GUIM_MOUSE_DOWN_LEFT,
|
||||
GUIM_MOUSE_DOWN_RIGHT,
|
||||
GUIM_MOUSE_RELEASE_LEFT,
|
||||
GUIM_MOUSE_RELEASE_RIGHT,
|
||||
GUIM_SETTINGS_UPDATED,
|
||||
GUIM_PRESSED
|
||||
};
|
||||
|
||||
// Recurse restrictions, when we recurse, if an object
|
||||
// is hidden for instance, you might want it to skip
|
||||
// the children also
|
||||
// Notice these are flags! and we don't really need one
|
||||
// for no restrictions, because then you'll just enter 0
|
||||
enum
|
||||
{
|
||||
GUIRR_HIDDEN=1,
|
||||
GUIRR_DISABLED=2
|
||||
};
|
||||
|
||||
// Typedefs
|
||||
typedef std::map<CStr, CGUIObject*> map_pObjects;
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Error declarations
|
||||
//--------------------------------------------------------
|
||||
typedef const char * PS_RESULT;
|
||||
DECLARE_ERROR(PS_FAIL)
|
||||
DECLARE_ERROR(PS_OK)
|
||||
DECLARE_ERROR(PS_NAME_TAKEN)
|
||||
DECLARE_ERROR(PS_OBJECT_FAIL)
|
||||
DECLARE_ERROR(PS_SETTING_FAIL)
|
||||
DECLARE_ERROR(PS_VALUE_INVALID)
|
||||
DECLARE_ERROR(PS_NEEDS_PGUI)
|
||||
DECLARE_ERROR(PS_NAME_AMBIGUITY)
|
||||
DECLARE_ERROR(PS_NEEDS_NAME)
|
||||
|
||||
|
||||
DECLARE_ERROR(PS_LEXICAL_FAIL)
|
||||
DECLARE_ERROR(PS_SYNTACTICAL_FAIL)
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Includes static functions that needs one template
|
||||
// argument.
|
||||
//--------------------------------------------------------
|
||||
// int is only to please functions that doesn't even use
|
||||
// T
|
||||
template <typename T=int>
|
||||
class GUI
|
||||
{
|
||||
// Private functions further ahead
|
||||
friend class CGUI;
|
||||
friend class CGUIObject;
|
||||
|
||||
public:
|
||||
//--------------------------------------------------------
|
||||
// Retrieves a setting by name
|
||||
// Input:
|
||||
// pObject Object pointer
|
||||
// Setting Setting by name
|
||||
// Output:
|
||||
// Value Stores value here
|
||||
// note type T!
|
||||
//--------------------------------------------------------
|
||||
static PS_RESULT GetSetting(CGUIObject *pObject, const CStr &Setting, T &Value)
|
||||
{
|
||||
if (pObject == NULL)
|
||||
return PS_OBJECT_FAIL;
|
||||
|
||||
if (!pObject->SettingExists(Setting))
|
||||
return PS_SETTING_FAIL;
|
||||
|
||||
// Set value
|
||||
Value = *(T*)((size_t)pObject+pObject->GetSettingsInfo()[Setting].m_Offset);
|
||||
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Sets a value by name using a real datatype as input
|
||||
// Input:
|
||||
// pObject Object pointer
|
||||
// Setting Setting by name
|
||||
// Value Sets value to this
|
||||
// note type T!
|
||||
//--------------------------------------------------------
|
||||
static PS_RESULT SetSetting(CGUIObject *pObject, const CStr &Setting, const T &Value)
|
||||
{
|
||||
if (pObject == NULL)
|
||||
return PS_OBJECT_FAIL;
|
||||
|
||||
if (!pObject->SettingExists(Setting))
|
||||
return PS_SETTING_FAIL;
|
||||
|
||||
// Set value
|
||||
// This better be the correct adress
|
||||
*(T*)((size_t)pObject+pObject->GetSettingsInfo()[Setting].m_Offset) = Value;
|
||||
|
||||
pObject->CheckSettingsValidity();
|
||||
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Retrieves a setting and object name
|
||||
// Input:
|
||||
// GUI GUI Object const ref
|
||||
// Object Object name
|
||||
// Setting Setting by name
|
||||
// Output:
|
||||
// Value Stores value here
|
||||
// note type T!
|
||||
//--------------------------------------------------------
|
||||
/* static PS_RESULT GetSetting(
|
||||
const CGUI &GUIinstance, const CStr &Object,
|
||||
const CStr &Setting, T &Value)
|
||||
{
|
||||
if (GUIinstance.ObjectExists(Object))
|
||||
return PS_OBJECT_FAIL;
|
||||
|
||||
// Retrieve pointer and call sibling function
|
||||
CGUIObject *pObject = GUIinstance.m_pAllObjects[Object];
|
||||
|
||||
return GetSetting(pObject, Setting, Value);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Sets a value by setting and object name using a real
|
||||
// datatype as input
|
||||
// Input:
|
||||
// GUI GUI Object const ref
|
||||
// Object Object name
|
||||
// Setting Setting by name
|
||||
// Value Sets value to this
|
||||
// note type T!
|
||||
//--------------------------------------------------------
|
||||
static PS_RESULT SetSetting(
|
||||
const CGUI &GUIinstance, const CStr &Object,
|
||||
const CStr &Setting, const T &Value)
|
||||
{
|
||||
if (GUIinstance.ObjectExists(Object))
|
||||
return PS_OBJECT_FAIL;
|
||||
|
||||
// Retrieve pointer and call sibling function
|
||||
CGUIObject *pObject = GUIinstance.m_pAllObjects[Object];
|
||||
|
||||
return SetSetting(pObject, Setting, Value);
|
||||
}
|
||||
*/
|
||||
//--------------------------------------------------------
|
||||
// This function returns the C++ structure of the
|
||||
// inputted string. For instance if you input
|
||||
// "0 0 10 10" and request a CRect, it will give you
|
||||
// a CRect(0,0,10,10).
|
||||
// This function is widely used within the GUI.
|
||||
// Input:
|
||||
// String The Value in string format
|
||||
// Return:
|
||||
// Returns the value in the structure T.
|
||||
//--------------------------------------------------------
|
||||
/* static T GetStringValue(const CStr &String)
|
||||
{
|
||||
if (typeid(T) == typeid(int))
|
||||
{
|
||||
return atoi(String.c_str());
|
||||
}
|
||||
|
||||
if (typeid(T) == typeid(float) ||
|
||||
typeid(T) == typeid(double))
|
||||
{
|
||||
return atof(String.c_str());
|
||||
}
|
||||
|
||||
if (typeid(T) == typeid(CRect))
|
||||
{
|
||||
(CRect)return CRect();
|
||||
}
|
||||
|
||||
if (typeid(T) == typeid(CColor))
|
||||
{
|
||||
return CColor();
|
||||
}
|
||||
|
||||
switch(typeid(T))
|
||||
{
|
||||
case typeid(int):
|
||||
return atoi(String);
|
||||
|
||||
case typeid(float):
|
||||
case typeid(double):
|
||||
return atof(String);
|
||||
|
||||
case typeid(CRect):
|
||||
return CRect(0,0,0,0);
|
||||
|
||||
case typeid(CColor):
|
||||
return CColor(0,0,0,0);
|
||||
|
||||
default:
|
||||
// Repport error unrecognized
|
||||
return T();
|
||||
}
|
||||
|
||||
// If this function is called T is unrecognized
|
||||
|
||||
// TODO repport error
|
||||
|
||||
return T();
|
||||
}
|
||||
*/
|
||||
/*
|
||||
static T<int> GetStringValue(const CStr &String)
|
||||
{
|
||||
return atoi(String.c_str());
|
||||
}
|
||||
*/
|
||||
// int
|
||||
/* static int GetStringValue(const CStr &String)
|
||||
{
|
||||
// If this function is called T is unrecognized
|
||||
|
||||
// TODO repport error
|
||||
|
||||
return 10;
|
||||
}
|
||||
*/
|
||||
|
||||
private:
|
||||
// templated typedef of function pointer
|
||||
typedef void (CGUIObject::*void_Object_pFunction_argT)(const T &arg);
|
||||
typedef void (CGUIObject::*void_Object_pFunction_argRefT)(T &arg);
|
||||
typedef void (CGUIObject::*void_Object_pFunction)();
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Recurses an object calling a function on itself
|
||||
// and all children (and so forth)
|
||||
// Input:
|
||||
// RR Recurse Restrictions
|
||||
// pObject Object to iterate
|
||||
// pFunc Function to recurse
|
||||
// Argument Argument of type T
|
||||
//--------------------------------------------------------
|
||||
static void RecurseObject(const int &RR, CGUIObject *pObject, void_Object_pFunction_argT pFunc, const T &Argument)
|
||||
{
|
||||
if (CheckIfRestricted(RR, pObject))
|
||||
return;
|
||||
|
||||
(pObject->*pFunc)(Argument);
|
||||
|
||||
// Iterate children
|
||||
vector_pObjects::iterator it;
|
||||
for (it = pObject->ChildrenItBegin(); it != pObject->ChildrenItEnd(); ++it)
|
||||
{
|
||||
RecurseObject(RR, *it, pFunc, Argument);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Same as above only with reference
|
||||
//--------------------------------------------------------
|
||||
static void RecurseObject(const int &RR, CGUIObject *pObject, void_Object_pFunction_argRefT pFunc, T &Argument)
|
||||
{
|
||||
if (CheckIfRestricted(RR, pObject))
|
||||
return;
|
||||
|
||||
(pObject->*pFunc)(Argument);
|
||||
|
||||
// Iterate children
|
||||
vector_pObjects::iterator it;
|
||||
for (it = pObject->ChildrenItBegin(); it != pObject->ChildrenItEnd(); ++it)
|
||||
{
|
||||
RecurseObject(RR, *it, pFunc, Argument);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Same as above only with no argument
|
||||
//--------------------------------------------------------
|
||||
static void RecurseObject(const int &RR, CGUIObject *pObject, void_Object_pFunction pFunc)
|
||||
{
|
||||
if (CheckIfRestricted(RR, pObject))
|
||||
return;
|
||||
|
||||
(pObject->*pFunc)();
|
||||
|
||||
// Iterate children
|
||||
vector_pObjects::iterator it;
|
||||
for (it = pObject->ChildrenItBegin(); it != pObject->ChildrenItEnd(); ++it)
|
||||
{
|
||||
RecurseObject(RR, *it, pFunc);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Sub functions
|
||||
static bool CheckIfRestricted(const int &RR, CGUIObject *pObject)
|
||||
{
|
||||
if (RR & GUIRR_HIDDEN)
|
||||
{
|
||||
if (pObject->GetBaseSettings().m_Hidden)
|
||||
return true;
|
||||
}
|
||||
if (RR & GUIRR_DISABLED)
|
||||
{
|
||||
if (pObject->GetBaseSettings().m_Enabled)
|
||||
return true;
|
||||
}
|
||||
|
||||
// false means not restricted
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Post includes
|
||||
//--------------------------------------------------------
|
||||
#include "CGUIObject.h"
|
||||
#include "CGUISettingsObject.h"
|
||||
#include "CGUIButtonBehavior.h"
|
||||
#include "CButton.h"
|
||||
#include "CGUISprite.h"
|
||||
#include "CGUI.h"
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Prototypes
|
||||
//--------------------------------------------------------
|
||||
|
||||
|
||||
#endif
|
52
source/gui/XercesErrorHandler.cpp
Executable file
52
source/gui/XercesErrorHandler.cpp
Executable file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Xerces Error Handler for Prometheus (and the GUI)
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
*/
|
||||
|
||||
///#include "nemesis.h"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Includes
|
||||
// ---------------------------------------------------------------------------
|
||||
#include <xercesc/sax/SAXParseException.hpp>
|
||||
#include "XercesErrorHandler.h"
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
void XercesErrorHandler::warning(const SAXParseException&)
|
||||
{
|
||||
//
|
||||
// Ignore all warnings.
|
||||
//
|
||||
}
|
||||
|
||||
void XercesErrorHandler::error(const SAXParseException& toCatch)
|
||||
{
|
||||
fSawErrors = true;
|
||||
/* cerr << "Error at file \"" << StrX(toCatch.getSystemId())
|
||||
<< "\", line " << toCatch.getLineNumber()
|
||||
<< ", column " << toCatch.getColumnNumber()
|
||||
<< "\n Message: " << StrX(toCatch.getMessage()) << endl;
|
||||
|
||||
*/
|
||||
/// g_nemLog(" Error: %s", XMLString::transcode(toCatch.getMessage()));
|
||||
}
|
||||
|
||||
void XercesErrorHandler::fatalError(const SAXParseException& toCatch)
|
||||
{
|
||||
fSawErrors = true;
|
||||
/* cerr << "Fatal Error at file \"" << StrX(toCatch.getSystemId())
|
||||
<< "\", line " << toCatch.getLineNumber()
|
||||
<< ", column " << toCatch.getColumnNumber()
|
||||
<< "\n Message: " << StrX(toCatch.getMessage()) << endl;
|
||||
*/
|
||||
/// g_nemLog(" Error: %s", XMLString::transcode(toCatch.getMessage()));
|
||||
}
|
||||
|
||||
void XercesErrorHandler::resetErrors()
|
||||
{
|
||||
fSawErrors = false;
|
||||
}
|
77
source/gui/XercesErrorHandler.h
Executable file
77
source/gui/XercesErrorHandler.h
Executable file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
Xerces Error Handler for Prometheus (and the GUI)
|
||||
by Gustav Larsson
|
||||
gee@pyro.nu
|
||||
|
||||
--Overview--
|
||||
|
||||
This is a class that that will let us output
|
||||
Xerces C++ Parser errors in our own Log
|
||||
or whatever, fit to Prometheus and foremost
|
||||
the GUI.
|
||||
|
||||
--More info--
|
||||
|
||||
http://xml.apache.org/xerces-c/apiDocs/classErrorHandler.html
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef XercesErrorHandler_H
|
||||
#define XercesErrorHandler_H
|
||||
|
||||
#include <xercesc/util/XercesDefs.hpp>
|
||||
#include <xercesc/sax/ErrorHandler.hpp>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
|
||||
class XercesErrorHandler : public ErrorHandler
|
||||
{
|
||||
public:
|
||||
// -----------------------------------------------------------------------
|
||||
// Constructors and Destructor
|
||||
// -----------------------------------------------------------------------
|
||||
XercesErrorHandler() :
|
||||
fSawErrors(false)
|
||||
{
|
||||
}
|
||||
|
||||
~XercesErrorHandler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Implementation of the error handler interface
|
||||
// -----------------------------------------------------------------------
|
||||
void warning(const SAXParseException& toCatch);
|
||||
void error(const SAXParseException& toCatch);
|
||||
void fatalError(const SAXParseException& toCatch);
|
||||
void resetErrors();
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Getter methods
|
||||
// -----------------------------------------------------------------------
|
||||
bool getSawErrors() const;
|
||||
|
||||
private:
|
||||
// -----------------------------------------------------------------------
|
||||
// Private data members
|
||||
//
|
||||
// fSawErrors
|
||||
// This is set if we get any errors, and is queryable via a getter
|
||||
// method. Its used by the main code to suppress output if there are
|
||||
// errors.
|
||||
// -----------------------------------------------------------------------
|
||||
bool fSawErrors;
|
||||
};
|
||||
|
||||
inline bool XercesErrorHandler::getSawErrors() const
|
||||
{
|
||||
return fSawErrors;
|
||||
}
|
||||
|
||||
#endif
|
13
source/gui/hello.xml
Executable file
13
source/gui/hello.xml
Executable file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1" standalone="no" ?>
|
||||
|
||||
<!DOCTYPE objects SYSTEM "objects.dtd">
|
||||
|
||||
<objects>
|
||||
<object name="Button2" type="button" size1024="120 120 220 220" style="hello" z="20" />
|
||||
|
||||
<object name="Button3" type="button" size1024="120 120 220 220" style="hello" z="20">
|
||||
<object name="Child" type="button" size1024="140 140 300 200" z="22">
|
||||
<object name="ChildsChilds" type="button" size1024="200 150 400 190" z="24"> </object>
|
||||
</object>
|
||||
</object>
|
||||
</objects>
|
208
source/gui/main.cpp
Executable file
208
source/gui/main.cpp
Executable file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
MAIN.CPP
|
||||
|
||||
Source
|
||||
|
||||
Nemesis Multimedia Framework Copyright (c) Gustav Larsson
|
||||
_______________________________________________________________________________
|
||||
******************************************************************************/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// IMPLEMENTATION HEADERS
|
||||
//=============================================================================
|
||||
//#pragma comment(lib,"../debug/nemesis.lib")
|
||||
///#include "nemesis.h"
|
||||
#include "GUI.h"
|
||||
///using namespace NEM_STL;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
|
||||
//=============================================================================
|
||||
//-----------------------------------------------------------------------------
|
||||
// IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
|
||||
//=============================================================================
|
||||
//-----------------------------------------------------------------------------
|
||||
// IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
|
||||
//=============================================================================
|
||||
//-----------------------------------------------------------------------------
|
||||
// IMPLEMENTATION PRIVATE DATA
|
||||
//=============================================================================
|
||||
//-----------------------------------------------------------------------------
|
||||
// INTERFACE DATA (GLOBALS)
|
||||
//=============================================================================
|
||||
///nemInput input;
|
||||
///nemFontNTF font;
|
||||
///nemConsoleGUIdefault consoleGUI;
|
||||
//-----------------------------------------------------------------------------
|
||||
// IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
|
||||
//=============================================================================
|
||||
//-----------------------------------------------------------------------------
|
||||
// IMPLEMENTATION PRIVATE FUNCTIONS
|
||||
//=============================================================================
|
||||
/*/*
|
||||
void cmd_show_console(nemConsole& c, const string& strArguments)
|
||||
{
|
||||
bool bArg, bResult;
|
||||
bResult = string2bool(strArguments, bArg);
|
||||
|
||||
// Reset console string
|
||||
g_strConsole = "";
|
||||
|
||||
if (strArguments == "")
|
||||
{
|
||||
// toggle
|
||||
c.pGUI->active = !c.pGUI->active;
|
||||
}
|
||||
else
|
||||
if (!bResult)
|
||||
{
|
||||
c.submit("echo Error! Invalid paramter");
|
||||
}
|
||||
else c.pGUI->active = bArg;
|
||||
}
|
||||
*/
|
||||
CGUI gui;
|
||||
CButton *button2;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// INTERFACE FUNCTIONS
|
||||
//=============================================================================
|
||||
|
||||
// nemInit
|
||||
// ------------------------------------------------------------------| Function
|
||||
// Initalization goes here
|
||||
bool nemInit()
|
||||
{
|
||||
/*/*
|
||||
g_console.inputVariable("sys_windowName", nemConsoleVariable::createString("Test This") );
|
||||
|
||||
// Init console gui
|
||||
consoleGUI.init(&font);
|
||||
|
||||
g_console.inputCommand("show_console", nemConsoleCommand(&cmd_show_console));
|
||||
|
||||
// Setup console gui
|
||||
g_console.initUI(&consoleGUI, &input, 100);
|
||||
|
||||
g_console.submit("exec config.cfg");
|
||||
|
||||
g_console.pGUI->active = true;
|
||||
|
||||
// Init window, or quit
|
||||
if (!g_window.init())
|
||||
return 0;
|
||||
|
||||
input.init(NEM_KEYBOARD | NEM_MOUSE);
|
||||
*/
|
||||
|
||||
gui.Initialize(/*/*&input*/);
|
||||
|
||||
|
||||
gui.LoadXMLFile("hello.xml");
|
||||
gui.LoadXMLFile("sprite1.xml");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// nemInitGL
|
||||
// ------------------------------------------------------------------| Function
|
||||
// Initalization of GL goes here
|
||||
// will be called when switching to fullscreen and similiar
|
||||
bool nemInitGL()
|
||||
{
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glClearColor(1.0f, 1.0f, 1.5f, 0.5f);
|
||||
glClearDepth(1.0f);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
/// font.init("Small.ntf");
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glLoadIdentity();
|
||||
|
||||
/// font.print(g_screenWidth/2, g_screenHeight/2, CENTER, "<black>Loading...");
|
||||
|
||||
/// g_window.swapBuffers();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// nemMain
|
||||
// ------------------------------------------------------------------| Function
|
||||
// will continuously be called
|
||||
bool nemMain()
|
||||
{
|
||||
/*/*
|
||||
input.update();
|
||||
g_console.update();
|
||||
*/
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
glLoadIdentity();
|
||||
|
||||
gui.Process();
|
||||
//if (res2 != PS_OK)
|
||||
// g_console.submit("echo %s", res2);
|
||||
|
||||
/// if (input.kbPress(NEMK_G))
|
||||
{
|
||||
//button2 = gui.
|
||||
|
||||
/* bool hidden;
|
||||
GUI<bool>::GetSetting(gui, "Button2", "hidden", hidden);
|
||||
|
||||
hidden = !hidden;
|
||||
|
||||
GUI<bool>::SetSetting(gui, "Button2", "hidden", hidden);
|
||||
|
||||
g_console.submit("echo G %s", (hidden?"true":"false"));
|
||||
*/ }
|
||||
|
||||
// nemPush2D();
|
||||
gui.Draw();
|
||||
/*
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glColor3f(1,0,0);
|
||||
glVertex2i(input.mPosX, input.mPosY);
|
||||
glVertex2i(input.mPosX, input.mPosY-18);
|
||||
glVertex2i(input.mPosX+10, input.mPosY-12);
|
||||
glEnd();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
nemPop2D();
|
||||
*/
|
||||
//g_console.submit("echo --");
|
||||
|
||||
/// g_console.draw();
|
||||
|
||||
// finish up drawing
|
||||
/// g_window.swapBuffers();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// nemShutdown
|
||||
// ------------------------------------------------------------------| Function
|
||||
// All shutdown goes here
|
||||
bool nemShutdown()
|
||||
{
|
||||
/*/* input.shutdown();
|
||||
font.shutdown();
|
||||
consoleGUI.shutdown();
|
||||
*/
|
||||
gui.Destroy();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// INTERFACE CLASS BODIES
|
||||
//=============================================================================
|
||||
|
||||
/* End of MAIN.CPP
|
||||
******************************************************************************/
|
49
source/gui/objects.dtd
Executable file
49
source/gui/objects.dtd
Executable file
@ -0,0 +1,49 @@
|
||||
<!--
|
||||
GUI XML Files DTD
|
||||
|
||||
Root Element: <objects>
|
||||
|
||||
Version:
|
||||
-->
|
||||
|
||||
<!ELEMENT objects (object*)>
|
||||
<!ELEMENT object (#PCDATA|object|action)*>
|
||||
|
||||
<!--
|
||||
Base Settings
|
||||
-->
|
||||
<!ATTLIST object name CDATA #IMPLIED>
|
||||
<!ATTLIST object type CDATA #IMPLIED>
|
||||
<!ATTLIST object absolute (true|false) #IMPLIED>
|
||||
<!ATTLIST object disabled (true|false) #IMPLIED>
|
||||
<!ATTLIST object ghost (true|false) #IMPLIED>
|
||||
<!ATTLIST object hidden (true|false) #IMPLIED>
|
||||
<!ATTLIST object size1024 CDATA #IMPLIED>
|
||||
<!ATTLIST object style CDATA #IMPLIED>
|
||||
<!ATTLIST object z CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Setting Pool
|
||||
-->
|
||||
<!ATTLIST object font CDATA #IMPLIED>
|
||||
<!ATTLIST object input-initvalue-destroyed-at-focus (true|false) #IMPLIED>
|
||||
<!ATTLIST object rectcolor-selected CDATA #IMPLIED>
|
||||
<!ATTLIST object scrollbar (true|false) #IMPLIED>
|
||||
<!ATTLIST object scrollbar-style CDATA #IMPLIED>
|
||||
<!ATTLIST object sprite CDATA #IMPLIED>
|
||||
<!ATTLIST object sprite2 CDATA #IMPLIED>
|
||||
<!ATTLIST object sprite-disabled CDATA #IMPLIED>
|
||||
<!ATTLIST object sprite2-disabled CDATA #IMPLIED>
|
||||
<!ATTLIST object sprite-over CDATA #IMPLIED>
|
||||
<!ATTLIST object sprite2-over CDATA #IMPLIED>
|
||||
<!ATTLIST object sprite-pressed CDATA #IMPLIED>
|
||||
<!ATTLIST object square-side CDATA #IMPLIED>
|
||||
<!ATTLIST object textalign (left|center|right) #IMPLIED>
|
||||
<!ATTLIST object textcolor CDATA #IMPLIED>
|
||||
<!ATTLIST object textcolor-disabled CDATA #IMPLIED>
|
||||
<!ATTLIST object textcolor-over CDATA #IMPLIED>
|
||||
<!ATTLIST object textcolor-pressed CDATA #IMPLIED>
|
||||
<!ATTLIST object textcolor-selected CDATA #IMPLIED>
|
||||
<!ATTLIST object textvalign (top|center|bottom) #IMPLIED>
|
||||
<!ATTLIST object tooltip CDATA #IMPLIED>
|
||||
<!ATTLIST object tooltip-style CDATA #IMPLIED>
|
9
source/gui/sprite1.xml
Executable file
9
source/gui/sprite1.xml
Executable file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
|
||||
|
||||
<!DOCTYPE sprites SYSTEM "sprites.dtd">
|
||||
|
||||
<sprites>
|
||||
<sprite name="sprite1">
|
||||
<image texture="t1" />
|
||||
</sprite>
|
||||
</sprites>
|
28
source/gui/sprites.dtd
Executable file
28
source/gui/sprites.dtd
Executable file
@ -0,0 +1,28 @@
|
||||
<!--
|
||||
GUI XML Files DTD
|
||||
|
||||
Root Element: <sprites>
|
||||
|
||||
Version:
|
||||
-->
|
||||
|
||||
<!ELEMENT sprites (sprite*)>
|
||||
<!ELEMENT sprite (image+)>
|
||||
<!ELEMENT image (#PCDATA)>
|
||||
|
||||
<!--
|
||||
<sprite>
|
||||
-->
|
||||
<!ATTLIST sprite name CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
<image>
|
||||
-->
|
||||
<!ATTLIST image texture CDATA #IMPLIED>
|
||||
<!ATTLIST image pixel CDATA #IMPLIED>
|
||||
<!ATTLIST image percent CDATA #IMPLIED>
|
||||
<!ATTLIST image t_pixel CDATA #IMPLIED>
|
||||
<!ATTLIST image t_percent CDATA #IMPLIED>
|
||||
<!ATTLIST image backcolor CDATA #IMPLIED>
|
||||
<!ATTLIST image bordercolor CDATA #IMPLIED>
|
||||
<!ATTLIST image bordersize CDATA #IMPLIED>
|
310
source/lib/detect.cpp
Executable file
310
source/lib/detect.cpp
Executable file
@ -0,0 +1,310 @@
|
||||
// system detect
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
// things missing in POSIX, SDL, and OpenGL :P
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "win.h"
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "version.lib")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "detect.h"
|
||||
#include "ia32.h"
|
||||
#include "time.h"
|
||||
#include "ogl.h"
|
||||
#include "wsdl.h"
|
||||
|
||||
|
||||
// useful for choosing a video mode. not called by detect().
|
||||
// currently not implemented for non-Win32 systems (returns 800x600).
|
||||
void get_cur_resolution(int& xres, int& yres)
|
||||
{
|
||||
// guess
|
||||
xres = 800; yres = 600;
|
||||
|
||||
#ifdef _WIN32
|
||||
static DEVMODE dm;
|
||||
dm.dmSize = sizeof(dm);
|
||||
EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm);
|
||||
xres = dm.dmPelsWidth;
|
||||
yres = dm.dmPelsHeight;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
size_t tot_mem = 0;
|
||||
size_t avl_mem = 0;
|
||||
|
||||
void get_mem_status()
|
||||
{
|
||||
// Win32
|
||||
#ifdef _WIN32
|
||||
|
||||
MEMORYSTATUS ms;
|
||||
GlobalMemoryStatus(&ms);
|
||||
tot_mem = round_up(ms.dwTotalPhys, 1*MB);
|
||||
// fixes results for my machine - off by 528 KB. why?!
|
||||
avl_mem = ms.dwAvailPhys;
|
||||
|
||||
// Sys V derived (GNU/Linux, Solaris)
|
||||
#elif defined(_SC_PAGESIZE) && defined(_SC_AVPHYS_PAGES)
|
||||
|
||||
long page_size = sysconf(_SC_PAGESIZE);
|
||||
tot_mem = sysconf(_SC_PHYS_PAGES ) * page_size;
|
||||
avl_mem = sysconf(_SC_AVPHYS_PAGES) * page_size;
|
||||
|
||||
// BSD / Mac OS X
|
||||
#elif HAVE_SYSCTL && defined(HW_PHYSMEM)
|
||||
|
||||
size_t len = sizeof(tot_mem);
|
||||
int mib[2] = { CTL_HW, HW_PHYSMEM };
|
||||
sysctl(mib, 2, &tot_mem, &len, 0, 0);
|
||||
mib[1] = HW_USERMEM;
|
||||
sysctl(mib, 2, &avl_mem, &len, 0, 0);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
char gfx_card[64] = "unknown";
|
||||
char gfx_drv[128] = "unknown";
|
||||
|
||||
|
||||
// attempt to detect graphics card without OpenGL (in case ogl init fails,
|
||||
// or we want more detailed info). gfx_card[] is unchanged on failure.
|
||||
void get_gfx_card()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
// gfx card
|
||||
// EnumDisplayDevices is not available on Win95 or NT
|
||||
HMODULE h = LoadLibrary("user32.dll");
|
||||
int (__stdcall *_EnumDisplayDevices)(void*, u32, void*, u32);
|
||||
*(void**)&_EnumDisplayDevices = GetProcAddress(h, "EnumDisplayDevicesA");
|
||||
if(_EnumDisplayDevices)
|
||||
{
|
||||
DISPLAY_DEVICE dev;
|
||||
dev.cb = sizeof(dev);
|
||||
if(_EnumDisplayDevices(0, 0, &dev, 0))
|
||||
strcpy(gfx_card, (const char*)dev.DeviceString);
|
||||
}
|
||||
|
||||
// driver
|
||||
{
|
||||
// .. get driver DLL name
|
||||
static DEVMODE dm; // note: dmDriverVersion is something else
|
||||
dm.dmSize = sizeof(dm);
|
||||
if(!EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm))
|
||||
goto ver_fail;
|
||||
char drv_name[CCHDEVICENAME+4];
|
||||
strcpy(drv_name, (const char*)dm.dmDeviceName);
|
||||
strcat(drv_name, ".dll");
|
||||
// .. read the DLL's version info
|
||||
DWORD unused;
|
||||
DWORD ver_size = GetFileVersionInfoSize(drv_name, &unused);
|
||||
if(!ver_size)
|
||||
goto ver_fail;
|
||||
void* buf = malloc(ver_size);
|
||||
if(!buf)
|
||||
goto ver_fail;
|
||||
if(GetFileVersionInfo(drv_name, 0, ver_size, buf))
|
||||
{
|
||||
u16* lang; // -> 16 bit language ID, 16 bit codepage
|
||||
uint lang_len;
|
||||
int ret = VerQueryValue(buf, "\\VarFileInfo\\Translation", (void**)&lang, &lang_len);
|
||||
if(ret && lang && lang_len == 4)
|
||||
{
|
||||
char subblock[37];
|
||||
sprintf(subblock, "\\StringFileInfo\\%04X%04X\\ProductName", lang[0], lang[1]);
|
||||
const char* ver;
|
||||
uint len;
|
||||
if(VerQueryValue(buf, subblock, (void**)&ver, &len))
|
||||
strncpy(gfx_drv, ver, sizeof(gfx_drv));
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
ver_fail:;
|
||||
|
||||
#endif
|
||||
|
||||
// driver version: http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/009679.html
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CPU
|
||||
//
|
||||
|
||||
char cpu_type[49] = "unknown"; // processor brand string is 48 chars
|
||||
double cpu_freq = 0.f;
|
||||
|
||||
long cpu_caps = 0;
|
||||
long cpu_ext_caps = 0;
|
||||
|
||||
// -1 if detect not yet called, or cannot be determined
|
||||
int cpus = -1;
|
||||
int is_notebook = -1;
|
||||
int has_tsc = -1;
|
||||
|
||||
|
||||
static void get_cpu_info()
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
static char cpu_vendor[13];
|
||||
int family, model;
|
||||
|
||||
__asm
|
||||
{
|
||||
; make sure CPUID is supported (size opt.)
|
||||
pushfd
|
||||
or byte ptr [esp+2], 32
|
||||
popfd
|
||||
pushfd
|
||||
pop eax
|
||||
shr eax, 22 ; bit 21 toggled?
|
||||
jnc no_cpuid
|
||||
|
||||
; get vendor string
|
||||
xor eax, eax
|
||||
cpuid
|
||||
mov dword ptr [cpu_vendor], ebx
|
||||
mov dword ptr [cpu_vendor+4], edx
|
||||
mov dword ptr [cpu_vendor+8], ecx
|
||||
; (already 0 terminated)
|
||||
|
||||
; get CPU signature and std feature bits
|
||||
mov eax, 1
|
||||
cpuid
|
||||
mov [cpu_caps], edx
|
||||
mov edx, eax
|
||||
shr edx, 4
|
||||
and edx, 0x0f
|
||||
mov [model], edx
|
||||
shr eax, 8
|
||||
and eax, 0x0f
|
||||
mov [family], eax
|
||||
|
||||
; make sure CPUID ext functions are supported
|
||||
mov eax, 0x80000000
|
||||
cpuid
|
||||
cmp eax, 0x80000000
|
||||
jbe no_brand_str
|
||||
|
||||
; get CPU brand string (>= Athlon XP, P4)
|
||||
mov edi, offset cpu_type
|
||||
mov esi, -2 ; loop counter: -2 to 0
|
||||
$1: lea eax, [0x80000004+esi]
|
||||
cpuid
|
||||
stosd
|
||||
xchg eax, ebx
|
||||
stosd
|
||||
xchg eax, ecx
|
||||
stosd
|
||||
xchg eax, edx
|
||||
stosd
|
||||
inc esi
|
||||
jle $1
|
||||
; already 0 terminated
|
||||
|
||||
; get extended feature flags
|
||||
mov eax, 0x80000001
|
||||
cpuid
|
||||
mov [cpu_ext_caps], edx
|
||||
}
|
||||
|
||||
// strip (tm) from Athlon string
|
||||
if(!strncmp(cpu_type, "AMD Athlon(tm)", 14))
|
||||
memmove(cpu_type+10, cpu_type+14, 34);
|
||||
|
||||
// remove 2x (R) and CPU freq from P4 string
|
||||
float a; // not used; sscanf returns # fields actually stored
|
||||
if(sscanf(cpu_type, " Intel(R) Pentium(R) 4 CPU %fGHz", &a) == 1)
|
||||
strcpy(cpu_type, "Intel Pentium 4");
|
||||
|
||||
goto have_brand_str;
|
||||
|
||||
no_brand_str:
|
||||
|
||||
// AMD
|
||||
if(!strcmp(cpu_vendor, "AuthenticAMD"))
|
||||
{
|
||||
if(family == 6)
|
||||
strcpy(cpu_type, (model == 3)? "AMD Duron" : "AMD Athlon");
|
||||
}
|
||||
// Intel
|
||||
else if(!strcmp(cpu_vendor, "GenuineIntel"))
|
||||
{
|
||||
if(family == 6 && model >= 7)
|
||||
strcpy(cpu_type, "Intel Pentium III / Celeron");
|
||||
}
|
||||
|
||||
have_brand_str:
|
||||
|
||||
// calc CPU freq (count clocks in 50 ms)
|
||||
if(cpu_caps & TSC)
|
||||
{
|
||||
u64 clocks1 = rdtsc();
|
||||
|
||||
// .. wait at at least 50 ms
|
||||
double t1 = get_time();
|
||||
double t2;
|
||||
do
|
||||
t2 = get_time();
|
||||
while(t2 < t1 + 50e-3);
|
||||
|
||||
u64 clocks2 = rdtsc();
|
||||
|
||||
// .. freq = (clocks / 50 [ms]) / 50 [ms] * 1000
|
||||
// cpuid/rdtsc overhead is negligible
|
||||
cpu_freq = (__int64)(clocks2-clocks1) / (t2-t1);
|
||||
// VC6 can't convert u64 -> double, and we don't need full range
|
||||
}
|
||||
// don't bother with a WAG timing loop
|
||||
|
||||
no_cpuid:
|
||||
|
||||
#endif // #ifdef _M_IX86
|
||||
|
||||
#ifdef _WIN32
|
||||
HW_PROFILE_INFO hi;
|
||||
GetCurrentHwProfile(&hi);
|
||||
is_notebook = !(hi.dwDockInfo & DOCKINFO_DOCKED) ^
|
||||
!(hi.dwDockInfo & DOCKINFO_UNDOCKED);
|
||||
// both flags set <==> this is a desktop machine.
|
||||
// both clear is unspecified; we assume it's not a notebook.
|
||||
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
cpus = si.dwNumberOfProcessors;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void detect()
|
||||
{
|
||||
get_mem_status();
|
||||
get_gfx_card();
|
||||
get_cpu_info();
|
||||
}
|
90
source/lib/detect.h
Executable file
90
source/lib/detect.h
Executable file
@ -0,0 +1,90 @@
|
||||
// system detect
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#ifndef __DETECT_H__
|
||||
#define __DETECT_H__
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// useful for choosing a video mode. not called by detect().
|
||||
// currently not implemented for non-Win32 systems (returns 800x600).
|
||||
extern void get_cur_resolution(int& xres, int& yres);
|
||||
|
||||
|
||||
extern char gfx_card[64]; // default: "unknown"
|
||||
extern char gfx_drv[128]; // default: "unknown"
|
||||
|
||||
// attempt to detect graphics card without OpenGL (in case ogl init fails,
|
||||
// or we want more detailed info). gfx_card[] is unchanged on failure.
|
||||
extern void get_gfx_card();
|
||||
|
||||
|
||||
//
|
||||
// mem
|
||||
//
|
||||
|
||||
extern size_t tot_mem;
|
||||
extern size_t avl_mem;
|
||||
|
||||
// updates *_mem above
|
||||
extern void get_mem_status();
|
||||
|
||||
|
||||
//
|
||||
// CPU
|
||||
//
|
||||
|
||||
extern char cpu_type[];
|
||||
extern double cpu_freq;
|
||||
|
||||
enum
|
||||
{
|
||||
TSC = BIT(4),
|
||||
CMOV = BIT(15),
|
||||
MMX = BIT(23),
|
||||
SSE = BIT(25),
|
||||
SSE2 = BIT(26)
|
||||
};
|
||||
|
||||
extern long cpu_caps;
|
||||
|
||||
// define instead of enum to avoid stupid sign conversion warning
|
||||
#define EXT_3DNOW_PRO BIT(30)
|
||||
#define EXT_3DNOW BIT(31)
|
||||
|
||||
extern long cpu_ext_caps;
|
||||
|
||||
// -1 if detect not yet called, or cannot be determined
|
||||
extern int cpus;
|
||||
extern int is_notebook;
|
||||
extern int has_tsc;
|
||||
|
||||
|
||||
extern void detect();
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #ifndef __DETECT_H__
|
226
source/lib/font.cpp
Executable file
226
source/lib/font.cpp
Executable file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* OpenGL texture font
|
||||
*
|
||||
* Copyright (c) 2002 Jan Wassenberg
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contact info:
|
||||
* Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
* http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "font.h"
|
||||
#include "res.h"
|
||||
#include "tex.h"
|
||||
#include "ogl.h"
|
||||
#include "posix.h"
|
||||
#include "misc.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Handle tex;
|
||||
uint list_base;
|
||||
}
|
||||
FONT;
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
#include <ft2build.h>
|
||||
//#include FT_FREETYPE_H
|
||||
|
||||
|
||||
static FT_Library lib;
|
||||
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
FT_Done_FreeType(lib);
|
||||
}
|
||||
|
||||
|
||||
int build_font(const char* in_ttf, const char* out_fnt, const char* out_raw, int height)
|
||||
{
|
||||
if(!lib)
|
||||
{
|
||||
FT_Init_FreeType(&lib);
|
||||
atexit(cleanup);
|
||||
}
|
||||
|
||||
FT_Face face;
|
||||
if(FT_New_Face(lib, in_ttf, 0, &face))
|
||||
return -1;
|
||||
|
||||
FT_Set_Pixel_Sizes(face, 0, height);
|
||||
const int tex_dim = 256;
|
||||
const int w = 24, h = 24;
|
||||
|
||||
FILE* f = fopen(out_fnt, "w");
|
||||
if(!f)
|
||||
return -1;
|
||||
fprintf(f, "%s\n%d %d\n", out_raw, w, h); /* header */
|
||||
|
||||
u8* tex = (u8*)calloc(tex_dim*tex_dim, 2); /* GL_LUMINANCE_ALPHA fmt */
|
||||
|
||||
int x = 0, y = 0;
|
||||
|
||||
for(int c = 32; c < 128; c++) /* for each (printable) char */
|
||||
{
|
||||
FT_Load_Char(face, c, FT_LOAD_RENDER);
|
||||
const u8* bmp = face->glyph->bitmap.buffer;
|
||||
|
||||
/* copy glyph's bitmap into texture */
|
||||
for(int j = 0; j < face->glyph->bitmap.rows; j++)
|
||||
{
|
||||
u8* pos = &tex[(y+h-8-face->glyph->bitmap_top+j)*tex_dim*2 + (x+face->glyph->bitmap_left)*2];
|
||||
for(int i = 0; i < face->glyph->bitmap.width; i++)
|
||||
{
|
||||
*pos++ = *bmp; /* luminance */
|
||||
*pos++ = (*bmp)? 0xff : 0x00; /* alpha */
|
||||
bmp++;
|
||||
}
|
||||
}
|
||||
|
||||
x += w;
|
||||
if(x + w >= tex_dim)
|
||||
x = 0, y += h;
|
||||
|
||||
fprintf(f, "%d ", face->glyph->advance.x / 64);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
/* write texture */
|
||||
f = fopen(out_raw, "wb");
|
||||
fwrite(tex, 2, tex_dim*tex_dim, f);
|
||||
fclose(f);
|
||||
|
||||
free(tex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static void font_dtor(HDATA* hd)
|
||||
{
|
||||
FONT* font = (FONT*)hd->internal;
|
||||
glDeleteLists(font->list_base, 96);
|
||||
}
|
||||
|
||||
|
||||
u32 font_load(const char* fn)
|
||||
{
|
||||
void* p;
|
||||
size_t size;
|
||||
HDATA* hd;
|
||||
Handle h = res_load(fn, RES_FONT, font_dtor, p, size, hd);
|
||||
if(!h)
|
||||
return 0;
|
||||
|
||||
int pos; // current position in the file
|
||||
const char* file = (const char*)p;
|
||||
|
||||
// read header
|
||||
char tex_filename[PATH_MAX];
|
||||
int x_stride, y_stride; // glyph spacing in texture
|
||||
if(sscanf(file, "%s\n%d %d\n%n", tex_filename, &x_stride, &y_stride, &pos) != 3)
|
||||
{
|
||||
printf("Problem loading \"%s\": header is invalid", fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// read glyph widths
|
||||
int adv[128];
|
||||
for(int i = 32; i < 128; i++)
|
||||
{
|
||||
file += pos;
|
||||
if(sscanf(file, "%d %n", &adv[i], &pos) != 1)
|
||||
{
|
||||
printf("Problem loading \"%s\": glyph width array is invalid", fn);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// load glyph texture
|
||||
const Handle tex = tex_load(tex_filename);
|
||||
if(!tex)
|
||||
return 0;
|
||||
tex_upload(tex);
|
||||
|
||||
const int tex_dim = 256;
|
||||
const float du = (float)x_stride / (float)tex_dim;
|
||||
float u = 0, v = 0;
|
||||
|
||||
// create a display list for each glyph
|
||||
const uint list_base = glGenLists(128);
|
||||
for(int c = 32; c < 128; c++)
|
||||
{
|
||||
const float w = (float)adv[c], h = (float)y_stride; // glyph quad width/height
|
||||
const float tw = w / tex_dim, th = h / tex_dim; // texture space width/height
|
||||
|
||||
glNewList(list_base+c, GL_COMPILE);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(u, v+th); glVertex2f(0, 0);
|
||||
glTexCoord2f(u+tw, v+th); glVertex2f(w, 0);
|
||||
glTexCoord2f(u+tw, v); glVertex2f(w, h);
|
||||
glTexCoord2f(u, v); glVertex2f(0, h);
|
||||
glEnd();
|
||||
glTranslatef(w, 0, 0);
|
||||
glEndList();
|
||||
|
||||
u += du;
|
||||
if(u + du > 1.f)
|
||||
u = 0.f, v += th;
|
||||
}
|
||||
|
||||
FONT* font = (FONT*)hd->internal;
|
||||
font->tex = tex;
|
||||
font->list_base = list_base;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
int font_bind(const Handle h)
|
||||
{
|
||||
HDATA* hd = h_data(h, RES_FONT);
|
||||
if(!hd)
|
||||
return -1;
|
||||
FONT* font = (FONT*)hd->internal;
|
||||
|
||||
tex_bind(font->tex);
|
||||
glListBase(font->list_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void glprintf(const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buf[1024]; buf[1023] = 0;
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, sizeof(buf)-1, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
glCallLists(strlen(buf), GL_UNSIGNED_BYTE, buf);
|
||||
}
|
80
source/lib/font.h
Executable file
80
source/lib/font.h
Executable file
@ -0,0 +1,80 @@
|
||||
// OpenGL texture font
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#ifndef __FONT_H__
|
||||
#define __FONT_H__
|
||||
|
||||
#include "types.h"
|
||||
#include "res.h"
|
||||
|
||||
// load and return a handle to the font defined in <fn>
|
||||
extern u32 font_load(const char* fn);
|
||||
|
||||
// use the font referenced by h for all subsequent glprintf() calls
|
||||
extern int font_bind(Handle h);
|
||||
|
||||
// output text at current OpenGL modelview pos.
|
||||
// assumes ortho projection with texturing, alpha test, and blending enabled.
|
||||
// must bind a font before calling!
|
||||
extern void glprintf(const char* fmt, ...);
|
||||
|
||||
|
||||
#endif // #ifndef __FONT_H__
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EXAMPLE:
|
||||
|
||||
#include "font.h"
|
||||
|
||||
|
||||
u32 h;
|
||||
|
||||
void init()
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, xres, 0, yres, -1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.5);
|
||||
|
||||
h = font_load("font.fnt");
|
||||
if(!h)
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void render()
|
||||
{
|
||||
font_bind(h);
|
||||
glprintf("string");
|
||||
}
|
||||
|
||||
// FONT FILE FORMAT:
|
||||
%s // texture file name
|
||||
%d %d // width/height of glyphs in the texture
|
||||
%d [...] %d // advance width for chars 32..127
|
||||
|
||||
*/
|
45
source/lib/glext_funcs.h
Executable file
45
source/lib/glext_funcs.h
Executable file
@ -0,0 +1,45 @@
|
||||
// were these defined as real functions in gl.h already?
|
||||
|
||||
#ifndef REAL_GL_1_2_1
|
||||
FUNC(void, glMultiTexCoord2f, (int, float, float))
|
||||
#endif
|
||||
|
||||
#ifndef REAL_GL_1_3
|
||||
FUNC(void, glActiveTexture, (int))
|
||||
#endif
|
||||
|
||||
// EXT_swap_control
|
||||
FUNC(int, wglSwapIntervalEXT, (int))
|
||||
|
||||
// NV_vertex_array
|
||||
FUNC(void, glVertexArrayRangeNV, (int, void*))
|
||||
FUNC(void, glFlushVertexArrayRangeNV, ())
|
||||
FUNC(void*, wglAllocateMemoryNV, (int, float, float, float))
|
||||
FUNC(void, wglFreeMemoryNV, (void*))
|
||||
|
||||
// NV_fence
|
||||
FUNC(void, glGenFencesNV, (int, unsigned int*))
|
||||
FUNC(void, glDeleteFencesNV, (int, const unsigned int*))
|
||||
FUNC(void, glSetFenceNV, (unsigned int, int))
|
||||
FUNC(int, glTestFenceNV, (unsigned int))
|
||||
FUNC(void, glFinishFenceNV, (unsigned int))
|
||||
FUNC(int, glIsFenceNV, (unsigned int))
|
||||
FUNC(void, glGetFenceivNV, (unsigned int, int, int*))
|
||||
|
||||
// ARB_vertex_array_object
|
||||
FUNC(void, BindBufferARB, (int target, GLuint buffer))
|
||||
FUNC(void, DeleteBuffersARB, (GLsizei n, const GLuint* buffers))
|
||||
FUNC(void, GenBuffersARB, (GLsizei n, GLuint* buffers))
|
||||
FUNC(bool, IsBufferARB, (GLuint buffer))
|
||||
FUNC(void, BufferDataARB, (int target, GLsizeiptrARB size, const void* data, int usage))
|
||||
FUNC(void, BufferSubDataARB, (int target, GLintptrARB offset, GLsizeiptrARB size, const void* data))
|
||||
FUNC(void, GetBufferSubDataARB, (int target, GLintptrARB offset, GLsizeiptrARB size, void* data))
|
||||
FUNC(void*, MapBufferARB, (int target, int access))
|
||||
FUNC(bool, UnmapBufferARB, (int target))
|
||||
FUNC(void, GetBufferParameterivARB, (int target, int pname, int* params))
|
||||
FUNC(void, GetBufferPointervARB, (int target, int pname, void** params))
|
||||
|
||||
|
||||
|
||||
FUNC(void, glCompressedTexImage2DARB, (int, int, int, unsigned int, unsigned int, int, unsigned int, const void*))
|
||||
FUNC(void, glCompressedTexSubImage2DARB, (int, int, int, int, unsigned int, int, int, unsigned int, const void*))
|
49
source/lib/ia32.cpp
Executable file
49
source/lib/ia32.cpp
Executable file
@ -0,0 +1,49 @@
|
||||
#include "ia32.h"
|
||||
#include "types.h"
|
||||
#include "misc.h"
|
||||
|
||||
|
||||
#ifndef _M_IX86
|
||||
#error "#define _M_IX86 to enable IA-32 code"
|
||||
#endif
|
||||
|
||||
|
||||
inline u64 rdtsc()
|
||||
{
|
||||
u64 c;
|
||||
__asm
|
||||
{
|
||||
cpuid
|
||||
rdtsc
|
||||
mov dword ptr [c], eax
|
||||
mov dword ptr [c+4], edx
|
||||
}
|
||||
// 64 bit values are returned in edx:eax, but we do it the safe way
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
// change FPU control word (used to set precision)
|
||||
uint _control87(uint new_cw, uint mask)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
push eax
|
||||
fnstcw [esp]
|
||||
pop eax ; old_cw
|
||||
mov ecx, [new_cw]
|
||||
mov edx, [mask]
|
||||
and ecx, edx ; new_cw & mask
|
||||
not edx ; ~mask
|
||||
and eax, edx ; old_cw & ~mask
|
||||
or eax, ecx ; (old_cw & ~mask) | (new_cw & mask)
|
||||
push eax
|
||||
fldcw [esp]
|
||||
pop eax
|
||||
}
|
||||
|
||||
UNUSED(new_cw)
|
||||
UNUSED(mask)
|
||||
|
||||
return 0;
|
||||
}
|
23
source/lib/ia32.h
Executable file
23
source/lib/ia32.h
Executable file
@ -0,0 +1,23 @@
|
||||
#ifndef _M_IX86
|
||||
#define __IA32_H__
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef __IA32_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
extern u64 rdtsc();
|
||||
|
||||
|
||||
#ifndef _MCW_PC
|
||||
#define _MCW_PC 0x0300 // Precision Control
|
||||
#endif
|
||||
#ifndef _PC_24
|
||||
#define _PC_24 0x0000 // 24 bits
|
||||
#endif
|
||||
|
||||
extern uint _control87(uint new_cw, uint mask);
|
||||
|
||||
#endif // #ifndef __IA32_H__
|
164
source/lib/input.cpp
Executable file
164
source/lib/input.cpp
Executable file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* input layer (dispatch events to multiple handlers; record/playback events)
|
||||
*
|
||||
* Copyright (c) 2002 Jan Wassenberg
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contact info:
|
||||
* Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
* http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "input.h"
|
||||
|
||||
|
||||
#define MAX_HANDLERS 4
|
||||
|
||||
static IN_HANDLER handler_stack[MAX_HANDLERS];
|
||||
static int handler_stack_top = 0;
|
||||
|
||||
|
||||
int in_add_handler(IN_HANDLER handler)
|
||||
{
|
||||
if(handler_stack_top >= MAX_HANDLERS || !handler)
|
||||
return -1;
|
||||
|
||||
handler_stack[handler_stack_top++] = handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* send event to each handler (newest first) until one returns true */
|
||||
static void dispatch_event(const SDL_Event& event)
|
||||
{
|
||||
for(int i = handler_stack_top-1; i >= 0; i--)
|
||||
if(handler_stack[i](event))
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static enum
|
||||
{
|
||||
INIT, /* first call to in_record() or in_playback(): register cleanup routine */
|
||||
IDLE,
|
||||
RECORD,
|
||||
PLAYBACK
|
||||
}
|
||||
state = INIT;
|
||||
|
||||
static FILE* f;
|
||||
|
||||
extern u32 game_ticks;
|
||||
|
||||
static u32 time_adjust = 0;
|
||||
static u32 next_event_time;
|
||||
|
||||
|
||||
void in_stop()
|
||||
{
|
||||
if(f)
|
||||
{
|
||||
fclose(f);
|
||||
f = 0;
|
||||
}
|
||||
|
||||
state = IDLE;
|
||||
}
|
||||
|
||||
|
||||
int in_record(const char* fn)
|
||||
{
|
||||
if(state == INIT)
|
||||
atexit(in_stop);
|
||||
|
||||
in_stop();
|
||||
|
||||
f = fopen(fn, "wb");
|
||||
if(!f)
|
||||
return -1;
|
||||
|
||||
fwrite(&game_ticks, sizeof(u32), 1, f);
|
||||
|
||||
state = RECORD;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int in_playback(const char* fn)
|
||||
{
|
||||
if(state == INIT)
|
||||
atexit(in_stop);
|
||||
|
||||
in_stop();
|
||||
|
||||
f = fopen(fn, "rb");
|
||||
if(!f)
|
||||
return -1;
|
||||
|
||||
u32 rec_start_time;
|
||||
fread(&rec_start_time, sizeof(u32), 1, f);
|
||||
time_adjust = game_ticks-rec_start_time;
|
||||
|
||||
fread(&next_event_time, sizeof(u32), 1, f);
|
||||
next_event_time += time_adjust;
|
||||
|
||||
state = PLAYBACK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void in_get_events()
|
||||
{
|
||||
SDL_Event event;
|
||||
|
||||
while(state == PLAYBACK && next_event_time <= game_ticks)
|
||||
{
|
||||
fread(&event, sizeof(SDL_Event), 1, f);
|
||||
|
||||
/*
|
||||
* do this before dispatch_event(),
|
||||
* in case a handler calls in_stop() (setting f to 0)
|
||||
*/
|
||||
if(!fread(&next_event_time, sizeof(u32), 1, f))
|
||||
{
|
||||
in_stop();
|
||||
exit(0x73c07d);
|
||||
// TODO: 'disconnect'?
|
||||
}
|
||||
next_event_time += time_adjust;
|
||||
|
||||
dispatch_event(event);
|
||||
}
|
||||
|
||||
/* get new events */
|
||||
while(SDL_PollEvent(&event))
|
||||
{
|
||||
if(state == RECORD)
|
||||
{
|
||||
fwrite(&game_ticks, sizeof(u32), 1, f);
|
||||
fwrite(&event, sizeof(SDL_Event), 1, f);
|
||||
}
|
||||
|
||||
if(state == PLAYBACK)
|
||||
if(event.type == SDL_KEYDOWN)
|
||||
in_stop();
|
||||
|
||||
dispatch_event(event);
|
||||
}
|
||||
}
|
56
source/lib/input.h
Executable file
56
source/lib/input.h
Executable file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* input layer (dispatch events to multiple handlers; record/playback events)
|
||||
*
|
||||
* Copyright (c) 2002 Jan Wassenberg
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contact info:
|
||||
* Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
* http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
*/
|
||||
|
||||
#ifndef __INPUT_H__
|
||||
#define __INPUT_H__
|
||||
|
||||
|
||||
#include "wsdl.h"
|
||||
#include "types.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
extern u32 game_ticks;
|
||||
|
||||
|
||||
typedef bool (*IN_HANDLER)(const SDL_Event& event);
|
||||
|
||||
/*
|
||||
* register an input handler, which will receive all subsequent events first.
|
||||
* events are passed to other handlers if handler returns false.
|
||||
*/
|
||||
extern int in_add_handler(IN_HANDLER handler);
|
||||
|
||||
extern void in_get_events();
|
||||
|
||||
extern int in_record(const char* fn);
|
||||
extern int in_playback(const char* fn);
|
||||
extern void in_stop();
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef __INPUT_H__ */
|
130
source/lib/mem.cpp
Executable file
130
source/lib/mem.cpp
Executable file
@ -0,0 +1,130 @@
|
||||
// malloc layer for less fragmentation, alignment, and automatic release
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "types.h"
|
||||
#include "mem.h"
|
||||
#include "res.h"
|
||||
#include "misc.h"
|
||||
#include "posix.h"
|
||||
|
||||
|
||||
struct MEM
|
||||
{
|
||||
uint type;
|
||||
void* org_p; // MEM_HEAP only
|
||||
size_t size; // MEM_POOL only
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void heap_dtor(HDATA* hd)
|
||||
{
|
||||
MEM* mem = (MEM*)hd->internal;
|
||||
free(mem->org_p);
|
||||
}
|
||||
|
||||
|
||||
static void* heap_alloc(const size_t size, const int align, MEM& mem)
|
||||
{
|
||||
u8* org_p = (u8*)malloc(size+align-1);
|
||||
u8* p = (u8*)round_up((long)org_p, align);
|
||||
|
||||
mem.org_p = org_p;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static u8* pool;
|
||||
static size_t pool_pos;
|
||||
static const size_t POOL_CAP = 64*MB; // TODO: user editable
|
||||
|
||||
|
||||
static void pool_dtor(HDATA* hd)
|
||||
{
|
||||
MEM* mem = (MEM*)hd->internal;
|
||||
|
||||
ssize_t pool_ofs = (u8*)hd->p - (u8*)pool;
|
||||
// at end of pool? if so, 'free' it
|
||||
if(pool_ofs + mem->size == pool_pos)
|
||||
pool_pos -= mem->size;
|
||||
}
|
||||
|
||||
|
||||
static void* pool_alloc(const size_t size, const uint align, MEM& mem)
|
||||
{
|
||||
if(!pool)
|
||||
{
|
||||
pool = (u8*)mem_alloc(size, MEM_HEAP, align);
|
||||
if(!pool)
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ofs = round_up((long)pool+pool_pos, align) - (ulong)pool;
|
||||
if(ofs+size > POOL_CAP)
|
||||
return 0;
|
||||
|
||||
void* p = (u8*)pool + ofs;
|
||||
|
||||
mem.size = size;
|
||||
|
||||
pool_pos = ofs+size;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void mem_dtor(HDATA* hd)
|
||||
{
|
||||
MEM* mem = (MEM*)hd->internal;
|
||||
if(mem->type == MEM_HEAP)
|
||||
heap_dtor(hd);
|
||||
else if(mem->type == MEM_POOL)
|
||||
pool_dtor(hd);
|
||||
}
|
||||
|
||||
|
||||
void* mem_alloc(size_t size, const MemType type, const uint align, Handle* ph)
|
||||
{
|
||||
if(size == 0)
|
||||
size = 1;
|
||||
|
||||
HDATA* hd;
|
||||
Handle h = h_alloc(0, RES_MEM, mem_dtor, &hd);
|
||||
if(!h)
|
||||
return 0;
|
||||
|
||||
MEM& mem = (MEM&)hd->internal;
|
||||
|
||||
void* p;
|
||||
if(type == MEM_HEAP)
|
||||
p = heap_alloc(size, align, mem);
|
||||
else if(type == MEM_POOL)
|
||||
p = pool_alloc(size, align, mem);
|
||||
else
|
||||
{
|
||||
h_free(h, RES_MEM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(ph)
|
||||
*ph = h;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
int mem_free(void* p)
|
||||
{
|
||||
if(!p)
|
||||
return 1;
|
||||
|
||||
HDATA* hd;
|
||||
Handle h = h_find(p, RES_MEM, &hd);
|
||||
if(h)
|
||||
return h_free(h, RES_MEM);
|
||||
return -1;
|
||||
}
|
15
source/lib/mem.h
Executable file
15
source/lib/mem.h
Executable file
@ -0,0 +1,15 @@
|
||||
#ifndef __MEM_H__
|
||||
#define __MEM_H__
|
||||
|
||||
#include "res.h"
|
||||
|
||||
enum MemType
|
||||
{
|
||||
MEM_POOL,
|
||||
MEM_HEAP
|
||||
};
|
||||
|
||||
extern void* mem_alloc(size_t size, MemType type = MEM_HEAP, uint align = 1, Handle* ph = 0);
|
||||
extern int mem_free(void* p);
|
||||
|
||||
#endif // #ifndef __MEM_H__
|
62
source/lib/memcpy.cpp
Executable file
62
source/lib/memcpy.cpp
Executable file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* block prefetch memcpy for large, uncached arrays
|
||||
*
|
||||
* src and len must be multiples of CHUNK_SIZE.
|
||||
*/
|
||||
void memcpy_nt(void* dst, void* src, int len)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
push esi
|
||||
|
||||
mov edx, [dst]
|
||||
mov esi, [src]
|
||||
mov ecx, [len]
|
||||
shr ecx, 12 ; # chunks
|
||||
; smaller than sub ecx, CHUNK_SIZE below
|
||||
|
||||
main_loop:
|
||||
|
||||
; prefetch: touch each cache line in chunk
|
||||
; (backwards to prevent hardware prefetches)
|
||||
; add esi, CHUNK_SIZE
|
||||
prefetch_loop:
|
||||
mov eax, [esi-64]
|
||||
mov eax, [esi-128]
|
||||
sub esi, 128
|
||||
test esi, 4095 ; CHUNK_SIZE-1 (icc doesn't preprocess asm)
|
||||
jnz prefetch_loop
|
||||
|
||||
|
||||
; copy the chunk 64 bytes at a time
|
||||
write_loop:
|
||||
movq mm0, [esi]
|
||||
movq mm1, [esi+8]
|
||||
movq mm2, [esi+16]
|
||||
movq mm3, [esi+24]
|
||||
movq mm4, [esi+32]
|
||||
movq mm5, [esi+40]
|
||||
movq mm6, [esi+48]
|
||||
movq mm7, [esi+56]
|
||||
add esi, 64
|
||||
test esi, 4095 ; CHUNK_SIZE-1
|
||||
movntq [edx], mm0
|
||||
movntq [edx+8], mm1
|
||||
movntq [edx+16], mm2
|
||||
movntq [edx+24], mm3
|
||||
movntq [edx+32], mm4
|
||||
movntq [edx+40], mm5
|
||||
movntq [edx+48], mm6
|
||||
movntq [edx+56], mm7
|
||||
lea edx, [edx+64] ; leave flags intact
|
||||
jnz write_loop
|
||||
|
||||
dec ecx
|
||||
jnz main_loop
|
||||
|
||||
sfence
|
||||
emms
|
||||
|
||||
pop esi
|
||||
}
|
||||
}
|
238
source/lib/misc.cpp
Executable file
238
source/lib/misc.cpp
Executable file
@ -0,0 +1,238 @@
|
||||
// miscellany
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
|
||||
#include "time.h"
|
||||
#include "misc.h"
|
||||
|
||||
|
||||
#include <map>
|
||||
|
||||
|
||||
|
||||
// FNV1-A
|
||||
u32 fnv_hash(const char* str, size_t len)
|
||||
{
|
||||
u32 h = 0;
|
||||
|
||||
while(len--)
|
||||
{
|
||||
h ^= *(const u8*)str++;
|
||||
h *= 0x01000193;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
u16 bswap16(u16 x)
|
||||
{
|
||||
return (u16)(((x & 0xff) << 8) | (x >> 8));
|
||||
}
|
||||
|
||||
|
||||
u32 bswap32(u32 x)
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
|
||||
__asm
|
||||
{
|
||||
mov eax, [x]
|
||||
bswap eax
|
||||
mov [x], eax
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
u32 t = x;
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
x <<= 8;
|
||||
x |= t & 0xff;
|
||||
}
|
||||
|
||||
#endif
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
void bswap32(const u8* data, int cnt)
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
|
||||
UNUSED(data)
|
||||
UNUSED(cnt)
|
||||
|
||||
__asm
|
||||
{
|
||||
mov edx, [data]
|
||||
mov ecx, [cnt]
|
||||
$loop: mov eax, [edx]
|
||||
bswap eax
|
||||
mov [edx], eax
|
||||
add edx, 4
|
||||
dec ecx
|
||||
jnz $loop
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
u32* p = (u32*)data;
|
||||
for(int i = 0; i < cnt; i++, p++)
|
||||
*p = bswap32(*p);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool is_pow2(const int n)
|
||||
{
|
||||
return (n > 0) && !(n & (n-1));
|
||||
}
|
||||
|
||||
|
||||
// return -1 if not an integral power of 2,
|
||||
// otherwise the base2 logarithm
|
||||
|
||||
int ilog2(const int n)
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
|
||||
__asm
|
||||
{
|
||||
mov ecx, [n]
|
||||
or eax, -1 // return value
|
||||
lea edx, [ecx-1]
|
||||
test ecx, edx // power of 2?
|
||||
jnz $ret
|
||||
bsf eax, ecx
|
||||
$ret:
|
||||
mov [n], eax
|
||||
}
|
||||
|
||||
return n;
|
||||
|
||||
#else
|
||||
|
||||
if(n || n & (n-1))
|
||||
return -1;
|
||||
|
||||
int i = 1, j = 0;
|
||||
for(; i != n; i += i, j++)
|
||||
;
|
||||
return j;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int ilog2(const float x)
|
||||
{
|
||||
u32 i = (u32&)x;
|
||||
u32 exp = (i >> 23) & 0xff;
|
||||
return (int)exp - 127;
|
||||
}
|
||||
|
||||
|
||||
long round_up(long val, int multiple)
|
||||
{
|
||||
val += multiple-1;
|
||||
val -= val % multiple;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
u16 addusw(u16 x, u16 y)
|
||||
{
|
||||
u32 t = x;
|
||||
return min(t+y, 0xffff);
|
||||
}
|
||||
|
||||
|
||||
u16 subusw(u16 x, u16 y)
|
||||
{
|
||||
long t = x;
|
||||
return max(t-y, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// provide fminf for non-C99 compilers
|
||||
#ifndef HAVE_C99
|
||||
|
||||
float fminf(float a, float b)
|
||||
{
|
||||
return (a < b)? a : b;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// replaces pathetic MS libc implementation
|
||||
#if defined(_M_IX86) && defined(_WIN32)
|
||||
|
||||
double _ceil(double f)
|
||||
{
|
||||
double r;
|
||||
|
||||
const float _49 = 0.499999f;
|
||||
__asm
|
||||
{
|
||||
fld [f]
|
||||
fadd [_49]
|
||||
frndint
|
||||
fstp [r]
|
||||
}
|
||||
|
||||
UNUSED(f)
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// big endian!
|
||||
void base32(const int len, const u8* in, u8* out)
|
||||
{
|
||||
int bits = 0;
|
||||
u32 pool = 0;
|
||||
|
||||
static u8 tbl[33] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
if(bits < 5)
|
||||
{
|
||||
pool <<= 8;
|
||||
pool |= *in++;
|
||||
bits += 8;
|
||||
}
|
||||
|
||||
bits -= 5;
|
||||
int c = (pool >> bits) & 31;
|
||||
*out++ = tbl[c];
|
||||
}
|
||||
}
|
139
source/lib/misc.h
Executable file
139
source/lib/misc.h
Executable file
@ -0,0 +1,139 @@
|
||||
// miscellany
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#ifndef __MISC_H__
|
||||
#define __MISC_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
// bswap32 is overloaded!
|
||||
#ifdef __cplusplus
|
||||
//extern "C" {
|
||||
#endif
|
||||
|
||||
// avoid ICC warning about undefined macros in #if
|
||||
#undef HAVE_C99
|
||||
#ifdef __STDC_VERSION__
|
||||
#if __STDC_VERSION__ >= 199901L)
|
||||
#define HAVE_C99
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#define UNUSED(param) (void)param;
|
||||
|
||||
#define ONCE(code) { static bool done; if(!done) { code; }; done = true; }
|
||||
|
||||
|
||||
const u32 KB = 1 << 10;
|
||||
const u32 MB = 1 << 20;
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define DIR_SEP '\\'
|
||||
#else
|
||||
#define DIR_SEP '/'
|
||||
#endif
|
||||
|
||||
|
||||
extern u32 fnv_hash(const char* str, size_t len);
|
||||
|
||||
#ifdef _WIN32
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
#define BIT(n) (1ul << (n))
|
||||
|
||||
#ifndef min
|
||||
inline int min(int a, int b)
|
||||
{
|
||||
return (a < b)? a : b;
|
||||
}
|
||||
|
||||
inline int max(int a, int b)
|
||||
{
|
||||
return (a > b)? a : b;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern u16 addusw(u16 x, u16 y);
|
||||
extern u16 subusw(u16 x, u16 y);
|
||||
|
||||
|
||||
|
||||
extern u16 bswap16(u16);
|
||||
extern u32 bswap32(u32);
|
||||
|
||||
extern void bswap32(const u8* data, int cnt);
|
||||
|
||||
static inline u16 read_le16(const void* p)
|
||||
{
|
||||
#ifdef BIG_ENDIAN
|
||||
const u8* _p = (const u8*)p;
|
||||
return (u16)_p[0] | (u16)_p[1] << 8;
|
||||
#else
|
||||
return *(u16*)p;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline u32 read_le32(const void* p)
|
||||
{
|
||||
#ifdef BIG_ENDIAN
|
||||
u32 t = 0;
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
t <<= 8;
|
||||
t |= *(const u8*)p++;
|
||||
}
|
||||
return t;
|
||||
#else
|
||||
return *(u32*)p;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
extern bool is_pow2(int n);
|
||||
|
||||
|
||||
// return -1 if not an integral power of 2,
|
||||
// otherwise the base2 logarithm
|
||||
extern int ilog2(const int n);
|
||||
|
||||
|
||||
extern long round_up(long val, int multiple);
|
||||
|
||||
|
||||
// provide fminf for non-C99 compilers
|
||||
#ifndef HAVE_C99
|
||||
extern float fminf(float, float);
|
||||
#endif
|
||||
|
||||
extern double _ceil(double);
|
||||
|
||||
|
||||
// big endian!
|
||||
extern void base32(const int len, const u8* in, u8* out);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
//}
|
||||
#endif
|
||||
|
||||
#endif // #ifndef __MISC_H__
|
125
source/lib/ogl.cpp
Executable file
125
source/lib/ogl.cpp
Executable file
@ -0,0 +1,125 @@
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
#include "wsdl.h"
|
||||
#include "ogl.h"
|
||||
#include "detect.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "opengl32.lib")
|
||||
#pragma comment(lib, "glu32.lib")
|
||||
#endif
|
||||
|
||||
|
||||
// define extension function pointers
|
||||
extern "C"
|
||||
{
|
||||
#define FUNC(ret, name, params) ret (CALL_CONV *name) params;
|
||||
#include "glext_funcs.h"
|
||||
#undef FUNC
|
||||
}
|
||||
|
||||
|
||||
static const char* exts;
|
||||
|
||||
|
||||
// check if the extension <ext> is supported by the OpenGL implementation
|
||||
bool oglExtAvail(const char* ext)
|
||||
{
|
||||
assert(exts && "call oglInit before using this function");
|
||||
|
||||
const char *p = exts, *end;
|
||||
|
||||
// make sure ext is valid & doesn't contain spaces
|
||||
if(!ext || ext == '\0' || strchr(ext, ' '))
|
||||
return false;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
p = strstr(p, ext);
|
||||
if(!p)
|
||||
return false; // <ext> string not found - extension not supported
|
||||
end = p + strlen(ext); // end of current substring
|
||||
|
||||
// make sure the substring found is an entire extension string,
|
||||
// i.e. it starts and ends with ' '
|
||||
if(p == exts || *(p-1) == ' ') // valid start?
|
||||
if(*end == ' ' || *end == '\0') // valid end?
|
||||
return true;
|
||||
p = end;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void oglPrintErrors()
|
||||
{
|
||||
#define E(e) case e: printf("%s\n", #e); break;
|
||||
|
||||
for(;;)
|
||||
switch(glGetError())
|
||||
{
|
||||
case GL_NO_ERROR:
|
||||
return;
|
||||
|
||||
E(GL_INVALID_ENUM)
|
||||
E(GL_INVALID_VALUE)
|
||||
E(GL_INVALID_OPERATION)
|
||||
E(GL_STACK_OVERFLOW)
|
||||
E(GL_STACK_UNDERFLOW)
|
||||
E(GL_OUT_OF_MEMORY)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int max_tex_size; // [pixels]
|
||||
int tex_units;
|
||||
int max_VAR_elements = -1; // GF2: 64K; GF3: 1M
|
||||
bool tex_compression_avail; // S3TC / DXT{1,3,5}
|
||||
int video_mem; // [MB]; approximate
|
||||
|
||||
#include "time.h"
|
||||
|
||||
// call after each video mode change
|
||||
void oglInit()
|
||||
{
|
||||
exts = (const char*)glGetString(GL_EXTENSIONS);
|
||||
|
||||
// import functions
|
||||
#define FUNC(ret, name, params) *(void**)&name = SDL_GL_GetProcAddress(#name);
|
||||
#include "glext_funcs.h"
|
||||
#undef FUNC
|
||||
|
||||
// detect OpenGL / graphics card caps
|
||||
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size);
|
||||
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &tex_units);
|
||||
// make sure value is -1 if not supported
|
||||
if(oglExtAvail("GL_NV_vertex_array_range"))
|
||||
glGetIntegerv(GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV, &max_VAR_elements);
|
||||
|
||||
tex_compression_avail = oglExtAvail("GL_ARB_texture_compression") &&
|
||||
(oglExtAvail("GL_EXT_texture_compression_s3tc") || oglExtAvail("GL_S3_s3tc"));
|
||||
|
||||
video_mem = (SDL_GetVideoInfo()->video_mem) / 1048576; // [MB]
|
||||
// TODO: add sizeof(FB)?
|
||||
|
||||
// get graphics card name
|
||||
// .. don't overwrite if e.g. get_gfx_card already called
|
||||
if(!strcmp(gfx_card, "Unknown"))
|
||||
{
|
||||
char* v = (char*)glGetString(GL_VENDOR);
|
||||
if(v)
|
||||
strncpy(gfx_card, v, sizeof(gfx_card));
|
||||
|
||||
// reduce string to "ATI" or "NVIDIA"
|
||||
if(!strcmp(gfx_card, "ATI Technologies Inc."))
|
||||
gfx_card[3] = 0;
|
||||
if(!strcmp(gfx_card, "NVIDIA Corporation"))
|
||||
gfx_card[6] = 0;
|
||||
|
||||
char* r = (char*)glGetString(GL_RENDERER);
|
||||
if(r)
|
||||
strcat(gfx_card, r);
|
||||
}
|
||||
}
|
100
source/lib/ogl.h
Executable file
100
source/lib/ogl.h
Executable file
@ -0,0 +1,100 @@
|
||||
#ifndef __OGL_H__
|
||||
#define __OGL_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//
|
||||
// OpenGL header
|
||||
//
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WINGDIAPI
|
||||
#define WINGDIAPI __declspec(dllimport)
|
||||
#endif
|
||||
#ifndef CALLBACK
|
||||
#define CALLBACK __stdcall
|
||||
#endif
|
||||
#ifndef APIENTRY
|
||||
#define APIENTRY __stdcall
|
||||
#endif
|
||||
typedef unsigned short wchar_t; // for glu.h
|
||||
#endif // #ifndef _WIN32
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glu.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// glext
|
||||
//
|
||||
|
||||
// if gl.h provides real prototypes for 1.2 / 1.3 functions,
|
||||
// exclude the corresponding function pointers in glext_funcs.h
|
||||
#ifdef GL_VERSION_1_2_1
|
||||
#define REAL_GL_1_2_1
|
||||
#endif
|
||||
#ifdef GL_VERSION_1_3
|
||||
#define REAL_GL_1_3
|
||||
#endif
|
||||
|
||||
#undef GL_GLEXT_PROTOTYPES
|
||||
#ifdef __APPLE__
|
||||
#include <OpenGL/glext.h>
|
||||
#else
|
||||
#include <GL/glext.h>
|
||||
#endif
|
||||
|
||||
#define GL_TEXTURE_IMAGE_SIZE_ARB 0x86A0
|
||||
|
||||
|
||||
//
|
||||
// function pointer declarations
|
||||
//
|
||||
|
||||
#ifdef _WIN32
|
||||
#define CALL_CONV __stdcall
|
||||
#else
|
||||
#define CALL_CONV
|
||||
#endif
|
||||
|
||||
#define FUNC(ret, name, params) extern ret (CALL_CONV *name) params;
|
||||
#include "glext_funcs.h"
|
||||
#undef FUNC
|
||||
|
||||
// leave CALL_CONV defined for ogl.cpp
|
||||
|
||||
|
||||
|
||||
//
|
||||
// OpenGL util
|
||||
//
|
||||
|
||||
extern int max_tex_size; // [pixels]
|
||||
extern int tex_units;
|
||||
extern int max_VAR_elements; // GF2: 64K; GF3: 1M
|
||||
extern bool tex_compression_avail; // S3TC / DXT{1,3,5}
|
||||
extern int video_mem; // [MB]; approximate
|
||||
|
||||
|
||||
// check if the extension <ext> is supported by the OpenGL implementation
|
||||
extern bool oglExtAvail(const char* ext);
|
||||
|
||||
// print all OpenGL errors
|
||||
extern void oglPrintErrors();
|
||||
|
||||
// call before using any of the above, and after each mode change
|
||||
extern void oglInit();
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #ifndef __OGL_H__
|
510
source/lib/posix.cpp
Executable file
510
source/lib/posix.cpp
Executable file
@ -0,0 +1,510 @@
|
||||
// POSIX emulation for Win32
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
// collection of hacks :P
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
#include <process.h>
|
||||
|
||||
#include "posix.h"
|
||||
#include "win.h"
|
||||
#include "time.h"
|
||||
#include "misc.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// file
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
extern int aio_open(const char*, int, int);
|
||||
extern int aio_close(int);
|
||||
*/
|
||||
|
||||
int open(const char* fn, int mode, ...)
|
||||
{
|
||||
// /dev/tty? => COM?
|
||||
if(!strncmp(fn, "/dev/tty", 8))
|
||||
{
|
||||
static char port[] = "COM ";
|
||||
port[3] = (char)(fn[8]+1);
|
||||
fn = port;
|
||||
}
|
||||
|
||||
int fd = _open(fn, mode);
|
||||
|
||||
// open it for async I/O as well (_open defaults to deny_none sharing)
|
||||
if(fd > 2)
|
||||
aio_open(fn, mode, fd);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
int close(int fd)
|
||||
{
|
||||
aio_close(fd);
|
||||
return _close(fd);
|
||||
}
|
||||
|
||||
|
||||
int ioctl(int fd, int op, int* data)
|
||||
{
|
||||
HANDLE h = (HANDLE)((char*)0 + _get_osfhandle(fd));
|
||||
|
||||
switch(op)
|
||||
{
|
||||
case TIOCMGET:
|
||||
/* TIOCM_* mapped directly to MS_*_ON */
|
||||
GetCommModemStatus(h, (DWORD*)data);
|
||||
break;
|
||||
|
||||
case TIOCMBIS:
|
||||
/* only RTS supported */
|
||||
if(*data & TIOCM_RTS)
|
||||
EscapeCommFunction(h, SETRTS);
|
||||
else
|
||||
EscapeCommFunction(h, CLRRTS);
|
||||
break;
|
||||
|
||||
case TIOCMIWAIT:
|
||||
static DWORD mask;
|
||||
DWORD new_mask = 0;
|
||||
if(*data & TIOCM_CD)
|
||||
new_mask |= EV_RLSD;
|
||||
if(*data & TIOCM_CTS)
|
||||
new_mask |= EV_CTS;
|
||||
if(new_mask != mask)
|
||||
SetCommMask(h, mask = new_mask);
|
||||
WaitCommEvent(h, &mask, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// dir
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
char* realpath(const char* fn, char* path)
|
||||
{
|
||||
if(!GetFullPathName(fn, PATH_MAX, path, 0))
|
||||
return 0;
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
int mkdir(const char* path, mode_t)
|
||||
{
|
||||
return CreateDirectory(path, 0)? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
struct _DIR
|
||||
{
|
||||
WIN32_FIND_DATA fd;
|
||||
HANDLE handle;
|
||||
struct dirent ent; // must not be overwritten by calls for different dirs
|
||||
bool not_first;
|
||||
};
|
||||
|
||||
|
||||
DIR* opendir(const char* name)
|
||||
{
|
||||
DWORD fa = GetFileAttributes(name);
|
||||
if(fa == INVALID_FILE_ATTRIBUTES || !(fa & FILE_ATTRIBUTE_DIRECTORY))
|
||||
return 0;
|
||||
|
||||
_DIR* d = (_DIR*)calloc(sizeof(_DIR), 1);
|
||||
|
||||
char path[MAX_PATH+1];
|
||||
strncpy(path, name, MAX_PATH-2);
|
||||
strcat(path, "\\*");
|
||||
d->handle = FindFirstFile(path, &d->fd);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
struct dirent* readdir(DIR* dir)
|
||||
{
|
||||
_DIR* d = (_DIR*)dir;
|
||||
|
||||
if(d->not_first)
|
||||
if(!FindNextFile(d->handle, &d->fd))
|
||||
return 0;
|
||||
d->not_first = true;
|
||||
|
||||
d->ent.d_ino = 0;
|
||||
d->ent.d_name = &d->fd.cFileName[0];
|
||||
return &d->ent;
|
||||
}
|
||||
|
||||
|
||||
int closedir(DIR* dir)
|
||||
{
|
||||
_DIR* d = (_DIR*)dir;
|
||||
|
||||
FindClose(d->handle);
|
||||
|
||||
free(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// terminal
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static HANDLE std_h[2] = { (HANDLE)(((char*)0) + 3), (HANDLE)(((char*)0) + 7) };
|
||||
|
||||
|
||||
__declspec(naked) void _get_console()
|
||||
{ __asm jmp dword ptr [AllocConsole] }
|
||||
|
||||
__declspec(naked) void _hide_console()
|
||||
{ __asm jmp dword ptr [FreeConsole] }
|
||||
|
||||
|
||||
int tcgetattr(int fd, struct termios* termios_p)
|
||||
{
|
||||
if(fd > 2)
|
||||
return -1;
|
||||
HANDLE h = std_h[fd];
|
||||
|
||||
DWORD mode;
|
||||
GetConsoleMode(h, &mode);
|
||||
termios_p->c_lflag = mode & (ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tcsetattr(int fd, int /* optional_actions */, const struct termios* termios_p)
|
||||
{
|
||||
if(fd > 2)
|
||||
return -1;
|
||||
HANDLE h = std_h[fd];
|
||||
SetConsoleMode(h, (DWORD)termios_p->c_lflag);
|
||||
FlushConsoleInputBuffer(h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int poll(struct pollfd /* fds */[], int /* nfds */, int /* timeout */)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// thread
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
__declspec(naked) pthread_t pthread_self(void)
|
||||
{ __asm jmp dword ptr [GetCurrentThread] }
|
||||
|
||||
|
||||
int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param* param)
|
||||
{
|
||||
if(policy == SCHED_FIFO)
|
||||
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
|
||||
|
||||
HANDLE hThread = (HANDLE)((char*)0 + thread);
|
||||
|
||||
SetThreadPriority(hThread, param->sched_priority);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pthread_create(pthread_t* /* thread */, const void* /* attr */, void*(* func)(void*), void* arg)
|
||||
{
|
||||
/* can't use asm 'cause _beginthread might be a func ptr (with libc) */
|
||||
return (int)_beginthread((void(*)(void*))func, 0, arg);
|
||||
}
|
||||
|
||||
|
||||
static HANDLE m2h(pthread_mutex_t* m)
|
||||
{
|
||||
if(!m)
|
||||
return INVALID_HANDLE_VALUE;
|
||||
HANDLE h;
|
||||
__asm
|
||||
{
|
||||
mov edx, [m]
|
||||
mov eax, [edx]
|
||||
mov [h], eax
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t*)
|
||||
{
|
||||
if(!m)
|
||||
return -1;
|
||||
HANDLE h = CreateMutex(0, 0, 0);
|
||||
*m = ((char*)h - (char*)0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_mutex_lock(pthread_mutex_t* m)
|
||||
{
|
||||
return WaitForSingleObject(m2h(m), INFINITE) == WAIT_OBJECT_0? 0 : -1;
|
||||
}
|
||||
|
||||
int pthread_mutex_trylock(pthread_mutex_t* m)
|
||||
{
|
||||
return WaitForSingleObject(m2h(m), 0) == WAIT_OBJECT_0? 0 : -1;
|
||||
}
|
||||
|
||||
int pthread_mutex_unlock(pthread_mutex_t* m)
|
||||
{
|
||||
return ReleaseMutex(m2h(m))? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// time
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
int clock_gettime(clockid_t clock_id, struct timespec* tp)
|
||||
{
|
||||
static double start_t = -1.0;
|
||||
static time_t start_s;
|
||||
|
||||
if(start_t < 0.0)
|
||||
{
|
||||
start_s = time(0);
|
||||
start_t = get_time();
|
||||
}
|
||||
|
||||
if(clock_id != CLOCK_REALTIME)
|
||||
{
|
||||
// errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
double t = get_time();
|
||||
double dt = t-start_t;
|
||||
start_t = t;
|
||||
|
||||
int ds = (int)floor(dt);
|
||||
int dn = (int)floor((dt-ds) * 1.0e9);
|
||||
|
||||
tp->tv_sec = start_s + ds;
|
||||
tp->tv_nsec = 0 + dn;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int nanosleep(const struct timespec* rqtp, struct timespec* /* rmtp */)
|
||||
{
|
||||
int ms = (int)rqtp->tv_sec * 1000 + rqtp->tv_nsec / 1000000;
|
||||
if(ms > 0)
|
||||
Sleep(ms);
|
||||
else
|
||||
{
|
||||
struct timespec t1, t2;
|
||||
clock_gettime(CLOCK_REALTIME, &t1);
|
||||
int d_ns;
|
||||
do
|
||||
{
|
||||
clock_gettime(CLOCK_REALTIME, &t2);
|
||||
d_ns = (int)(t2.tv_sec-t1.tv_sec)*1000000000 + (t2.tv_nsec-t1.tv_nsec);
|
||||
}
|
||||
while(d_ns < rqtp->tv_nsec);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint sleep(uint sec)
|
||||
{
|
||||
Sleep(sec * 1000);
|
||||
|
||||
return sec;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// memory mapping
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void* mmap(void* start, unsigned int len, int prot, int flags, int fd, long offset)
|
||||
{
|
||||
if(!(flags & MAP_FIXED))
|
||||
start = 0;
|
||||
|
||||
/* interpret protection/mapping flags. */
|
||||
SECURITY_ATTRIBUTES sec = { sizeof(SECURITY_ATTRIBUTES), 0, 0 };
|
||||
DWORD flProtect = PAGE_READONLY; /* mapping object permission */
|
||||
DWORD dwAccess = FILE_MAP_READ; /* file map access permission */
|
||||
if(prot & PROT_WRITE)
|
||||
{
|
||||
flProtect = PAGE_READWRITE;
|
||||
|
||||
/* changes are shared & written to file */
|
||||
if(flags & MAP_SHARED)
|
||||
{
|
||||
sec.bInheritHandle = 1;
|
||||
dwAccess = FILE_MAP_ALL_ACCESS;
|
||||
}
|
||||
/* private copy on write mapping */
|
||||
else if(flags & MAP_PRIVATE)
|
||||
{
|
||||
flProtect = PAGE_WRITECOPY;
|
||||
dwAccess = FILE_MAP_COPY;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD len_hi = (u32)((u64)len >> 32), len_lo = (u32)len & 0xffffffff;
|
||||
|
||||
HANDLE hFile = (HANDLE)((char*)0 + _get_osfhandle(fd));
|
||||
HANDLE hMap = CreateFileMapping(hFile, &sec, flProtect, len_hi, len_lo, 0);
|
||||
|
||||
void* ptr = MapViewOfFileEx(hMap, dwAccess, len_hi, offset, len_lo, start);
|
||||
|
||||
/* file mapping object will be freed when ptr is unmapped */
|
||||
CloseHandle(hMap);
|
||||
|
||||
if(!ptr || (flags & MAP_FIXED && ptr != start))
|
||||
return MAP_FAILED;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
int munmap(void* start, unsigned int /* len */)
|
||||
{
|
||||
return UnmapViewOfFile(start) - 1; /* 0: success; -1: fail */
|
||||
}
|
||||
|
||||
|
||||
int uname(struct utsname* un)
|
||||
{
|
||||
if(!un)
|
||||
return -1;
|
||||
|
||||
static OSVERSIONINFO vi;
|
||||
vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
GetVersionEx(&vi);
|
||||
|
||||
// OS implementation name
|
||||
const char* family = "??";
|
||||
int ver = (vi.dwMajorVersion << 8) | vi.dwMinorVersion;
|
||||
if(vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
||||
family = (ver == 0x045a)? "ME" : "9x";
|
||||
if(vi.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
||||
{
|
||||
if(ver == 0x0500)
|
||||
family = "2k";
|
||||
else if(ver == 0x0501)
|
||||
family = "XP";
|
||||
else
|
||||
family = "NT";
|
||||
}
|
||||
sprintf(un->sysname, "Win%s", family);
|
||||
|
||||
// release info
|
||||
const char* vs = vi.szCSDVersion;
|
||||
int sp;
|
||||
if(sscanf(vs, "Service Pack %d", &sp) == 1)
|
||||
sprintf(un->release, "SP %d", sp);
|
||||
else
|
||||
{
|
||||
const char* release = "";
|
||||
if(vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
||||
{
|
||||
if(!strcmp(vs, " C"))
|
||||
release = "OSR2";
|
||||
else if(!strcmp(vs, " A"))
|
||||
release = "SE";
|
||||
}
|
||||
strcpy(un->release, release);
|
||||
}
|
||||
|
||||
// version
|
||||
sprintf(un->version, "%lu.%02lu.%lu", vi.dwMajorVersion, vi.dwMinorVersion, vi.dwBuildNumber & 0xffff);
|
||||
|
||||
// node name
|
||||
u32 buf_size = sizeof(un->nodename);
|
||||
GetComputerName(un->nodename, &buf_size);
|
||||
|
||||
// hardware type
|
||||
static SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
|
||||
if(si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
|
||||
strcpy(un->machine, "AMD64");
|
||||
else
|
||||
strcpy(un->machine, "x86");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
u16_t htons(u16_t s)
|
||||
{
|
||||
return (s >> 8) || ((s & 0xff) << 8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void entry(void)
|
||||
{
|
||||
// alloc __pio, __iob?
|
||||
// replace CRT init?
|
||||
|
||||
// header also removed to prevent calling Winsock functions
|
||||
#ifndef NO_WINSOCK
|
||||
char d[1024];
|
||||
WSAStartup(0x0101, d);
|
||||
#endif
|
||||
|
||||
mainCRTStartup();
|
||||
}
|
498
source/lib/posix.h
Executable file
498
source/lib/posix.h
Executable file
@ -0,0 +1,498 @@
|
||||
// POSIX emulation for Win32
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h>
|
||||
#include <aio.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define __POSIX_H__ // => rest of header ignored
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef __POSIX_H__
|
||||
#define __POSIX_H__
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define IMP(ret, name, param) extern "C" __declspec(dllimport) ret __stdcall name param;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// <inttypes.h>
|
||||
//
|
||||
|
||||
typedef unsigned short u16_t;
|
||||
|
||||
|
||||
//
|
||||
// <sys/types.h>
|
||||
//
|
||||
|
||||
#ifndef _SIZE_T_DEFINED // compatibility with VC stdlib.h
|
||||
#define _SIZE_T_DEFINED
|
||||
typedef unsigned long size_t;
|
||||
#endif
|
||||
|
||||
typedef long ssize_t;
|
||||
|
||||
|
||||
//
|
||||
// <limits.h>
|
||||
//
|
||||
|
||||
#define PATH_MAX 260
|
||||
|
||||
|
||||
//
|
||||
// <errno.h>
|
||||
//
|
||||
|
||||
#define EINPROGRESS 100000
|
||||
|
||||
/*
|
||||
enum
|
||||
{
|
||||
EINPROGRESS = 1000, // Operation in progress.
|
||||
ENOMEM // Not enough space.
|
||||
EACCES, // Permission denied.
|
||||
EADDRINUSE, // Address in use.
|
||||
EADDRNOTAVAIL, // Address not available.
|
||||
EAGAIN, // Resource unavailable, try again (may be the same value as EWOULDBLOCK]).
|
||||
EALREADY, // Connection already in progress.
|
||||
EBADF, // Bad file descriptor.
|
||||
ECANCELED, // Operation canceled.
|
||||
ECONNABORTED, // Connection aborted.
|
||||
ECONNREFUSED, // Connection refused.
|
||||
ECONNRESET, // Connection reset.
|
||||
EDOM, // Mathematics argument out of domain of IMPtion.
|
||||
EEXIST, // File exists.
|
||||
EFAULT, // Bad address.
|
||||
EHOSTUNREACH, // Host is unreachable.
|
||||
EINTR, // Interrupted IMPtion.
|
||||
EINVAL, // Invalid argument.
|
||||
EISCONN, // Socket is connected.
|
||||
EISDIR, // Is a directory.
|
||||
ENAMETOOLONG, // Filename too long.
|
||||
ENETDOWN, // Network is down.
|
||||
ENETRESET, // Connection aborted by network.
|
||||
ENETUNREACH, // Network unreachable.
|
||||
ENOENT, // No such file or directory.
|
||||
ENOEXEC, // Executable file format error.
|
||||
|
||||
ENOSPC, // No space left on device.
|
||||
ENOSYS, // IMPtion not supported.
|
||||
ENOTCONN, // The socket is not connected.
|
||||
ENOTDIR, // Not a directory.
|
||||
ENOTEMPTY, // Directory not empty.
|
||||
ENOTSOCK, // Not a socket.
|
||||
ENOTSUP, // Not supported.
|
||||
EOVERFLOW, // Value too large to be stored in data type.
|
||||
EPERM, // Operation not permitted.
|
||||
EPIPE, // Broken pipe.
|
||||
EPROTO, // Protocol error.
|
||||
ERANGE, // Result too large.
|
||||
ETIMEDOUT, // Connection timed out.
|
||||
EWOULDBLOCK // Operation would block (may be the same value as EAGAIN]).
|
||||
|
||||
};
|
||||
*/
|
||||
|
||||
//
|
||||
// <time.h>
|
||||
//
|
||||
|
||||
typedef long time_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CLOCK_REALTIME
|
||||
}
|
||||
clockid_t;
|
||||
|
||||
struct timespec
|
||||
{
|
||||
time_t tv_sec;
|
||||
long tv_nsec;
|
||||
};
|
||||
|
||||
extern time_t time(time_t*);
|
||||
extern int clock_gettime(clockid_t clock_id, struct timespec* tp);
|
||||
extern int nanosleep(const struct timespec* rqtp, struct timespec* rmtp);
|
||||
|
||||
|
||||
//
|
||||
// sys/stat.h
|
||||
//
|
||||
|
||||
typedef unsigned short ino_t;
|
||||
typedef unsigned int mode_t;
|
||||
typedef long off_t;
|
||||
typedef unsigned int dev_t;
|
||||
|
||||
// struct stat defined in VC sys/stat.h
|
||||
|
||||
#define stat _stat
|
||||
|
||||
extern int mkdir(const char*, mode_t);
|
||||
|
||||
|
||||
//
|
||||
// dirent.h
|
||||
//
|
||||
|
||||
typedef void DIR;
|
||||
|
||||
struct dirent
|
||||
{
|
||||
ino_t d_ino;
|
||||
char* d_name;
|
||||
};
|
||||
|
||||
extern DIR* opendir(const char* name);
|
||||
extern struct dirent* readdir(DIR*);
|
||||
extern int closedir(DIR*);
|
||||
|
||||
|
||||
//
|
||||
// <sys/mman.h>
|
||||
//
|
||||
|
||||
#define PROT_READ 0x01 // page can be read
|
||||
#define PROT_WRITE 0x02 // page can be written
|
||||
|
||||
#define MAP_SHARED 0x01 // share changes across processes
|
||||
#define MAP_PRIVATE 0x02 // private copy on write mapping
|
||||
#define MAP_FIXED 0x04
|
||||
|
||||
#define MAP_FAILED 0
|
||||
|
||||
extern void* mmap(void* start, unsigned int len, int prot, int flags, int fd, long offset);
|
||||
extern int munmap(void* start, unsigned int len);
|
||||
|
||||
|
||||
//
|
||||
// <fcntl.h>
|
||||
//
|
||||
|
||||
// values from MS _open - do not change!
|
||||
#define O_RDONLY 0x0000 // open for reading only
|
||||
#define O_WRONLY 0x0001 // open for writing only
|
||||
#define O_RDWR 0x0002 // open for reading and writing
|
||||
#define O_APPEND 0x0008 // writes done at eof
|
||||
#define O_CREAT 0x0100 // create and open file
|
||||
#define O_TRUNC 0x0200 // open and truncate
|
||||
#define O_EXCL 0x0400 // open only if file doesn't already exist
|
||||
#define O_BINARY 0x8000 // file mode is binary (untranslated)
|
||||
|
||||
#define O_NONBLOCK 0x1000000
|
||||
|
||||
extern int open(const char* fn, int mode, ...);
|
||||
|
||||
|
||||
//
|
||||
// <unistd.h>
|
||||
//
|
||||
|
||||
#define F_OK 0
|
||||
#define R_OK 1
|
||||
#define W_OK 2
|
||||
#define X_OK 4
|
||||
|
||||
#define read _read
|
||||
#define write _write
|
||||
|
||||
extern int close(int);
|
||||
extern int access(const char*, int);
|
||||
extern int chdir(const char*);
|
||||
|
||||
extern unsigned int sleep(unsigned int sec);
|
||||
IMP(int, gethostname, (char* name, size_t namelen))
|
||||
|
||||
|
||||
|
||||
//
|
||||
// <stdlib.h>
|
||||
//
|
||||
|
||||
extern char* realpath(const char*, char*);
|
||||
|
||||
|
||||
//
|
||||
// <signal.h>
|
||||
//
|
||||
|
||||
union sigval
|
||||
{
|
||||
int sival_int; // Integer signal value.
|
||||
void* sival_ptr; // Pointer signal value.
|
||||
};
|
||||
|
||||
struct sigevent
|
||||
{
|
||||
int sigev_notify; // notification mode
|
||||
int sigev_signo; // signal number
|
||||
union sigval sigev_value; // signal value
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// <termios.h>
|
||||
//
|
||||
|
||||
#define TCSANOW 0
|
||||
|
||||
struct termios
|
||||
{
|
||||
long c_lflag;
|
||||
};
|
||||
|
||||
#define ICANON 2 // do not change - correspond to ENABLE_LINE_INPUT / ENABLE_ECHO_INPUT
|
||||
#define ECHO 4
|
||||
|
||||
extern int tcgetattr(int fd, struct termios* termios_p);
|
||||
extern int tcsetattr(int fd, int optional_actions, const struct termios* termios_p);
|
||||
|
||||
|
||||
//
|
||||
// <sched.h>
|
||||
//
|
||||
|
||||
struct sched_param
|
||||
{
|
||||
int sched_priority;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SCHED_RR,
|
||||
SCHED_FIFO,
|
||||
SCHED_OTHER
|
||||
};
|
||||
|
||||
#define sched_get_priority_max(policy) 15 // TIME_CRITICAL
|
||||
#define sched_get_priority_min(policy) -15 // IDLE
|
||||
|
||||
|
||||
//
|
||||
// <pthread.h>
|
||||
//
|
||||
|
||||
typedef unsigned int pthread_t;
|
||||
|
||||
extern pthread_t pthread_self();
|
||||
extern int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param* param);
|
||||
extern int pthread_create(pthread_t* thread, const void* attr, void*(*IMP)(void*), void* arg);
|
||||
|
||||
typedef unsigned int pthread_mutex_t;
|
||||
typedef void pthread_mutexattr_t;
|
||||
|
||||
extern int pthread_mutex_init(pthread_mutex_t*, const pthread_mutexattr_t*);
|
||||
extern int pthread_mutex_destroy(pthread_mutex_t*);
|
||||
|
||||
extern int pthread_mutex_lock(pthread_mutex_t*);
|
||||
extern int pthread_mutex_trylock(pthread_mutex_t*);
|
||||
extern int pthread_mutex_unlock(pthread_mutex_t*);
|
||||
|
||||
|
||||
|
||||
//
|
||||
// <sys/socket.h>
|
||||
//
|
||||
|
||||
typedef unsigned long socklen_t;
|
||||
typedef unsigned short sa_family_t;
|
||||
|
||||
// Win32 values - do not change
|
||||
#define SOCK_STREAM 1
|
||||
#define SOCK_DGRAM 2
|
||||
#define AF_INET 2
|
||||
|
||||
IMP(int, socket, (int, int, int))
|
||||
IMP(int, setsockopt, (int, int, int, const void*, socklen_t))
|
||||
|
||||
struct sockaddr;
|
||||
|
||||
|
||||
//
|
||||
// <netinet/in.h>
|
||||
//
|
||||
|
||||
typedef unsigned long in_addr_t;
|
||||
typedef unsigned short in_port_t;
|
||||
|
||||
struct in_addr
|
||||
{
|
||||
in_addr_t s_addr;
|
||||
};
|
||||
|
||||
struct sockaddr_in
|
||||
{
|
||||
sa_family_t sin_family;
|
||||
in_port_t sin_port;
|
||||
struct in_addr sin_addr;
|
||||
unsigned char sin_zero[8];
|
||||
};
|
||||
|
||||
#define INADDR_ANY 0
|
||||
#define INADDR_NONE ((in_addr_t)-1)
|
||||
|
||||
#define IPPROTO_IP 0
|
||||
#define IP_ADD_MEMBERSHIP 5
|
||||
#define IP_DROP_MEMBERSHIP 6
|
||||
|
||||
struct ip_mreq
|
||||
{
|
||||
struct in_addr imr_multiaddr; /* multicast group to join */
|
||||
struct in_addr imr_interface; /* interface to join on */
|
||||
};
|
||||
|
||||
//
|
||||
// <netdb.h>
|
||||
//
|
||||
|
||||
struct hostent
|
||||
{
|
||||
char* h_name; // Official name of the host.
|
||||
char** h_aliases; // A pointer to an array of pointers to
|
||||
// alternative host names, terminated by a
|
||||
// null pointer.
|
||||
short h_addrtype; // Address type.
|
||||
short h_length; // The length, in bytes, of the address.
|
||||
char** h_addr_list; // A pointer to an array of pointers to network
|
||||
// addresses (in network byte order) for the host,
|
||||
// terminated by a null pointer.
|
||||
};
|
||||
|
||||
IMP(struct hostent*, gethostbyname, (const char *name))
|
||||
|
||||
#define h_error WSAGetLastError()
|
||||
#define TRY_AGAIN 11002
|
||||
|
||||
|
||||
//
|
||||
// <arpa/inet.h>
|
||||
//
|
||||
|
||||
extern u16_t htons(u16_t hostshort);
|
||||
#define ntohs htons
|
||||
|
||||
IMP(in_addr_t, inet_addr, (const char*))
|
||||
IMP(char*, inet_ntoa, (in_addr))
|
||||
IMP(int, accept, (int, struct sockaddr*, socklen_t*))
|
||||
IMP(int, bind, (int, const struct sockaddr*, socklen_t))
|
||||
IMP(int, connect, (int, const struct sockaddr*, socklen_t))
|
||||
IMP(int, listen, (int, int))
|
||||
IMP(ssize_t, recv, (int, void*, size_t, int))
|
||||
IMP(ssize_t, send, (int, const void*, size_t, int))
|
||||
IMP(ssize_t, sendto, (int, const void*, size_t, int, const struct sockaddr*, socklen_t))
|
||||
IMP(ssize_t, recvfrom, (int, void*, size_t, int, struct sockaddr*, socklen_t*))
|
||||
|
||||
//
|
||||
// <poll.h>
|
||||
//
|
||||
|
||||
struct pollfd
|
||||
{
|
||||
int fd;
|
||||
short int events, revents;
|
||||
};
|
||||
|
||||
#define POLLIN 1
|
||||
|
||||
extern int poll(struct pollfd[], int, int);
|
||||
|
||||
|
||||
//
|
||||
// <sys/utsname.h>
|
||||
//
|
||||
|
||||
struct utsname
|
||||
{
|
||||
char sysname[9]; // Name of this implementation of the operating system.
|
||||
char nodename[16]; // Name of this node within an implementation-defined
|
||||
// communications network.
|
||||
// Win9x requires this minimum buffer size.
|
||||
char release[9]; // Current release level of this implementation.
|
||||
char version[16]; // Current version level of this release.
|
||||
char machine[9]; // Name of the hardware type on which the system is running.
|
||||
};
|
||||
|
||||
extern int uname(struct utsname*);
|
||||
|
||||
|
||||
//
|
||||
// serial port IOCTL
|
||||
//
|
||||
|
||||
// use with TIOCMBIS
|
||||
#define TIOCM_RTS 1
|
||||
|
||||
// use with TIOCMGET or TIOCMIWAIT
|
||||
#define TIOCM_CD 0x80 // MS_RLSD_ON
|
||||
#define TIOCM_CTS 0x10 // MS_CTS_ON
|
||||
|
||||
enum
|
||||
{
|
||||
TIOCMBIS, // set control line
|
||||
TIOCMGET, // get line state
|
||||
TIOCMIWAIT // wait for status change
|
||||
};
|
||||
|
||||
extern int ioctl(int fd, int op, int* data);
|
||||
|
||||
#define FIONREAD 0
|
||||
|
||||
|
||||
|
||||
extern void _get_console();
|
||||
extern void _hide_console();
|
||||
|
||||
|
||||
#include "posix/aio.h"
|
||||
|
||||
extern void entry(void);
|
||||
extern void mainCRTStartup();
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif // #ifndef __POSIX_H__
|
357
source/lib/res.cpp
Executable file
357
source/lib/res.cpp
Executable file
@ -0,0 +1,357 @@
|
||||
// handle-based resource manager
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
#include "types.h"
|
||||
#include "unzip.h"
|
||||
#include "posix.h"
|
||||
#include "misc.h"
|
||||
#include "res.h"
|
||||
#include "vfs.h"
|
||||
|
||||
// handle (32 bits)
|
||||
// .. make sure this is the same handle we opened
|
||||
static const uint TAG_BITS = 16;
|
||||
// .. index into array => = log2(max open handles)
|
||||
static const uint IDX_BITS = 12;
|
||||
|
||||
static const uint OWNER_BITS = 4;
|
||||
static const uint TYPE_BITS = 4;
|
||||
static const uint REF_BITS = 8;
|
||||
|
||||
struct Res
|
||||
{
|
||||
u32 key;
|
||||
u32 tag : TAG_BITS;
|
||||
u32 type : TYPE_BITS;
|
||||
u32 owner : OWNER_BITS;
|
||||
u32 refs : REF_BITS;
|
||||
};
|
||||
|
||||
static const ulong res_array_cap = 1ul << IDX_BITS;
|
||||
static const uint owner_cap = 1ul << OWNER_BITS;
|
||||
|
||||
// static allocation for simplicity; mem usage isn't significant
|
||||
static Res res_array[res_array_cap];
|
||||
static int first_free = -1;
|
||||
static int max_idx = -1; // index of last in-use entry
|
||||
|
||||
// array of pages for better locality, less fragmentation
|
||||
static const uint PAGE_SIZE = 4096;
|
||||
static const uint hdata_per_page = PAGE_SIZE / sizeof(HDATA);
|
||||
static const uint num_pages = res_array_cap / hdata_per_page;
|
||||
static HDATA* pages[num_pages];
|
||||
|
||||
static void(*dtors[owner_cap])(HDATA*);
|
||||
|
||||
|
||||
|
||||
static Handle handle(const int idx)
|
||||
{
|
||||
const Res& r = res_array[idx];
|
||||
return (r.tag) << IDX_BITS | (u32)idx;
|
||||
}
|
||||
|
||||
|
||||
static int h_idx(const Handle h, const uint owner)
|
||||
{
|
||||
int idx = h & ((1 << IDX_BITS)-1);
|
||||
const Res& r = res_array[idx];
|
||||
|
||||
u32 tag = h >> IDX_BITS;
|
||||
if(!tag || r.tag != tag || r.owner != owner)
|
||||
return -1;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
static HDATA* h_data(const int idx)
|
||||
{
|
||||
HDATA*& page = pages[idx / hdata_per_page];
|
||||
if(!page)
|
||||
{
|
||||
page = (HDATA*)calloc(PAGE_SIZE, 1);
|
||||
if(!page)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return &page[idx % hdata_per_page];
|
||||
}
|
||||
|
||||
|
||||
static int h_free(const int idx)
|
||||
{
|
||||
Res& r = res_array[idx];
|
||||
if(--r.refs)
|
||||
return 0;
|
||||
|
||||
HDATA* hd = h_data(idx);
|
||||
if(hd)
|
||||
{
|
||||
if(dtors[r.owner])
|
||||
dtors[r.owner](hd);
|
||||
memset(hd, 0, sizeof(HDATA));
|
||||
}
|
||||
|
||||
memset(&r, 0, sizeof(r));
|
||||
|
||||
if(first_free == -1 || idx < first_free)
|
||||
first_free = idx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
// close open handles
|
||||
for(i = 0; i < max_idx; i++)
|
||||
h_free(i);
|
||||
|
||||
// free internal data space
|
||||
for(i = 0; i < (int)num_pages; i++)
|
||||
{
|
||||
free(pages[i]);
|
||||
pages[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Handle h_find(const void* p, uint owner, HDATA** phd)
|
||||
{
|
||||
const Res* r = res_array;
|
||||
|
||||
for(int idx = 0; idx <= max_idx; idx++, r++)
|
||||
{
|
||||
if(r->owner != owner)
|
||||
continue;
|
||||
|
||||
HDATA* hd = h_data(idx);
|
||||
if(hd && hd->p == p)
|
||||
{
|
||||
if(phd)
|
||||
*phd = hd;
|
||||
return handle(idx);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Handle h_find(const u32 key, uint owner, HDATA** phd)
|
||||
{
|
||||
int idx;
|
||||
const Res* r = res_array;
|
||||
|
||||
// already have first free entry cached - just search
|
||||
if(first_free != -1)
|
||||
{
|
||||
for(idx = 0; idx <= max_idx; idx++, r++)
|
||||
if(r->key == key && r->owner == owner)
|
||||
goto found;
|
||||
}
|
||||
// search and remember first free entry (slower)
|
||||
else
|
||||
{
|
||||
for(idx = 0; idx <= max_idx; idx++, r++)
|
||||
if(!r->tag && first_free == -1)
|
||||
first_free = idx;
|
||||
else if(r->key == key && r->owner == owner)
|
||||
goto found;
|
||||
}
|
||||
|
||||
// not found
|
||||
return 0;
|
||||
|
||||
found:
|
||||
Handle h = handle(idx);
|
||||
if(phd)
|
||||
{
|
||||
HDATA* hd = h_data(h, owner);
|
||||
if(!hd)
|
||||
return 0;
|
||||
*phd = hd;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
Handle h_alloc(const u32 key, const uint owner, DTOR dtor, HDATA** phd)
|
||||
{
|
||||
ONCE(atexit(cleanup))
|
||||
|
||||
if(owner >= owner_cap)
|
||||
return 0;
|
||||
|
||||
if(dtor)
|
||||
{
|
||||
// registering a second dtor for owner
|
||||
// if(dtors[owner] && dtors[owner] != dtor)
|
||||
// return 0;
|
||||
dtors[owner] = dtor;
|
||||
}
|
||||
|
||||
int idx;
|
||||
Res* r = res_array;
|
||||
|
||||
HDATA* hd;
|
||||
Handle h;
|
||||
if(key)
|
||||
{
|
||||
h = h_find(key, owner, &hd);
|
||||
if(h)
|
||||
{
|
||||
idx = h_idx(h, owner);
|
||||
r = &res_array[idx];
|
||||
|
||||
assert(hd->size != 0);
|
||||
|
||||
if(r->refs == (1ul << REF_BITS))
|
||||
{
|
||||
assert(!"h_alloc: too many references to a handle - increase REF_BITS");
|
||||
return 0;
|
||||
}
|
||||
r->refs++;
|
||||
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
// cached
|
||||
if(first_free != -1)
|
||||
{
|
||||
idx = first_free;
|
||||
r = &res_array[idx];
|
||||
}
|
||||
// search res_array for first entry
|
||||
else
|
||||
for(idx = 0; idx < res_array_cap; idx++, r++)
|
||||
if(!r->tag)
|
||||
break;
|
||||
|
||||
// check if next entry is free
|
||||
if(idx+1 < res_array_cap && !(r+1)->key)
|
||||
first_free = idx+1;
|
||||
else
|
||||
first_free = -1;
|
||||
|
||||
if(idx >= res_array_cap)
|
||||
{
|
||||
assert(!"h_alloc: too many open handles (increase IDX_BITS)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(idx > max_idx)
|
||||
max_idx = idx;
|
||||
|
||||
static u32 tag;
|
||||
if(++tag >= (1 << TAG_BITS))
|
||||
{
|
||||
assert(!"h_alloc: tag overflow - may not notice stale handle reuse (increase TAG_BITS)");
|
||||
tag = 1;
|
||||
}
|
||||
|
||||
r->key = key;
|
||||
r->tag = tag;
|
||||
r->owner = owner;
|
||||
|
||||
h = handle(idx);
|
||||
|
||||
// caller wants HDATA* returned
|
||||
if(phd)
|
||||
{
|
||||
HDATA* hd = h_data(h, owner);
|
||||
// not enough mem - fail
|
||||
if(!hd)
|
||||
{
|
||||
h_free(h, owner);
|
||||
return 0;
|
||||
}
|
||||
*phd = hd;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
int h_free(const Handle h, const uint owner)
|
||||
{
|
||||
int idx = h_idx(h, owner);
|
||||
if(idx >= 0)
|
||||
return h_free(idx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HDATA* h_data(const Handle h, const uint owner)
|
||||
{
|
||||
int idx = h_idx(h, owner);
|
||||
if(idx >= 0)
|
||||
return h_data(idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Handle res_load(const char* fn, uint type, DTOR dtor, void*& p, size_t& size, HDATA*& hd)
|
||||
{
|
||||
p = 0;
|
||||
size = 0;
|
||||
hd = 0;
|
||||
|
||||
u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
// TODO: fn is usually a constant; pass fn len if too slow
|
||||
|
||||
Handle h = h_alloc(fn_hash, type, dtor, &hd);
|
||||
if(!h)
|
||||
return 0;
|
||||
|
||||
// already open - return a reference
|
||||
if(hd->size)
|
||||
return h;
|
||||
|
||||
Handle hf = vfs_open(fn);
|
||||
int err = vfs_read(hf, p, size, 0);
|
||||
vfs_close(hf);
|
||||
if(err < 0)
|
||||
return 0;
|
||||
|
||||
if(!p)
|
||||
{
|
||||
h_free(h, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hd->p = p;
|
||||
hd->size = size;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
71
source/lib/res.h
Executable file
71
source/lib/res.h
Executable file
@ -0,0 +1,71 @@
|
||||
// handle based caching resource manager
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#ifndef __RES_H__
|
||||
#define __RES_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
// handle type (for 'type safety' - can't use a texture handle as a sound)
|
||||
enum
|
||||
{
|
||||
RES_TEX = 1,
|
||||
RES_FONT,
|
||||
RES_SOUND,
|
||||
RES_ZFILE,
|
||||
RES_ZARCHIVE,
|
||||
RES_VFILE,
|
||||
|
||||
RES_MMAP,
|
||||
RES_MEM
|
||||
};
|
||||
|
||||
|
||||
typedef unsigned long Handle;
|
||||
|
||||
const int HDATA_INTERNAL_SIZE = 24;
|
||||
|
||||
|
||||
struct HDATA
|
||||
{
|
||||
void* p;
|
||||
size_t size;
|
||||
u8 internal[HDATA_INTERNAL_SIZE];
|
||||
};
|
||||
|
||||
typedef void(*DTOR)(HDATA*);
|
||||
|
||||
extern Handle h_alloc(u32 key, uint type, DTOR dtor = 0, HDATA** phd = 0);
|
||||
extern int h_free(Handle h, uint type);
|
||||
|
||||
// find and return a handle by type and associated key (typically filename hash)
|
||||
// currently O(n).
|
||||
extern Handle h_find(u32 key, uint type, HDATA** phd = 0);
|
||||
|
||||
// same as above, but search for a pointer the handle references
|
||||
extern Handle h_find(const void* p, uint type, HDATA** phd = 0);
|
||||
|
||||
// get a handle's associated data.
|
||||
// returns 0 if the handle is invalid, or <type> doesn't match
|
||||
extern HDATA* h_data(Handle h, uint type);
|
||||
|
||||
extern Handle res_load(const char* fn, uint type, DTOR dtor, void*& p, size_t& size, HDATA*& hd);
|
||||
|
||||
|
||||
#endif // #ifndef __RES_H__
|
769
source/lib/tex.cpp
Executable file
769
source/lib/tex.cpp
Executable file
@ -0,0 +1,769 @@
|
||||
// OpenGL texturing
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
// supported formats: DDS, TGA, PNG, JP2, BMP, RAW
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
#include "tex.h"
|
||||
#include "ogl.h"
|
||||
#include "res.h"
|
||||
#include "misc.h"
|
||||
|
||||
#define NO_JP2
|
||||
#define NO_PNG
|
||||
|
||||
#ifndef NO_JP2
|
||||
#include <jasper/jasper.h>
|
||||
#endif
|
||||
|
||||
#ifndef NO_PNG
|
||||
#include <png.h>
|
||||
#pragma comment(lib, "libpng.lib")
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DDS
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef NO_DDS
|
||||
|
||||
// converts 4 character string to u32 for easy comparison
|
||||
// can't pass code as string, and use s[0]..s[3], because
|
||||
// VC6/7 don't realize the macro is constant (and it's used in a switch{})
|
||||
#ifdef BIG_ENDIAN
|
||||
#define FOURCC(a,b,c,d) ( ((u32)a << 24) | ((u32)b << 16) | \
|
||||
((u32)c << 8 ) | ((u32)d << 0 ) )
|
||||
#else
|
||||
#define FOURCC(a,b,c,d) ( ((u32)a << 0 ) | ((u32)b << 8 ) | \
|
||||
((u32)c << 16) | ((u32)d << 24) )
|
||||
#endif
|
||||
|
||||
// modified from ddraw header
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct { u32 lo, hi; } DDCOLORKEY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 dwSize; // size of structure
|
||||
u32 dwFlags; // pixel format flags
|
||||
u32 dwFourCC; // (FOURCC code)
|
||||
u32 dwRGBBitCount; // how many bits per pixel
|
||||
u32 dwRBitMask; // mask for red bit
|
||||
u32 dwGBitMask; // mask for green bits
|
||||
u32 dwBBitMask; // mask for blue bits
|
||||
u32 dwRGBAlphaBitMask; // mask for alpha channel
|
||||
}
|
||||
DDPIXELFORMAT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 dwCaps; // capabilities of surface wanted
|
||||
u32 dwCaps2;
|
||||
u32 dwCaps3;
|
||||
u32 dwCaps4;
|
||||
}
|
||||
DDSCAPS2;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 dwSize; // size of the DDSURFACEDESC structure
|
||||
u32 dwFlags; // determines what fields are valid
|
||||
u32 dwHeight; // height of surface to be created
|
||||
u32 dwWidth; // width of input surface
|
||||
u32 dwLinearSize; // surface size
|
||||
u32 dwBackBufferCount; // number of back buffers requested
|
||||
u32 dwMipMapCount; // number of mip-map levels requestde
|
||||
u32 dwAlphaBitDepth; // depth of alpha buffer requested
|
||||
u32 dwReserved; // reserved
|
||||
void* lpSurface; // pointer to the associated surface memory
|
||||
DDCOLORKEY unused[4]; // src/dst overlay, blt
|
||||
DDPIXELFORMAT ddpfPixelFormat; // pixel format description of the surface
|
||||
DDSCAPS2 ddsCaps; // direct draw surface capabilities
|
||||
u32 dwTextureStage; // stage in multitexture cascade
|
||||
}
|
||||
DDSURFACEDESC2;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
static inline bool dds_valid(const u8* ptr, size_t size)
|
||||
{
|
||||
UNUSED(size) // only need first 4 chars
|
||||
|
||||
return *(u32*)ptr == FOURCC('D','D','S',' ');
|
||||
}
|
||||
|
||||
|
||||
// TODO: DXT1a?
|
||||
static int dds_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
{
|
||||
const char* err = 0;
|
||||
|
||||
const DDSURFACEDESC2* surf = (const DDSURFACEDESC2*)(ptr+4);
|
||||
const u32 hdr_size = 4+sizeof(DDSURFACEDESC2);
|
||||
if(size < hdr_size)
|
||||
err = "header not completely read";
|
||||
else
|
||||
{
|
||||
const u32 w = read_le32(&surf->dwWidth);
|
||||
const u32 h = read_le32(&surf->dwHeight);
|
||||
const u32 ddsd_size = read_le32(&surf->dwSize);
|
||||
const u32 img_size = read_le32(&surf->dwLinearSize);
|
||||
const u32 mipmaps = read_le32(&surf->dwMipMapCount);
|
||||
|
||||
const u8* img = ptr + hdr_size;
|
||||
|
||||
uint fmt = 0;
|
||||
switch(surf->ddpfPixelFormat.dwFourCC) // endian-independent
|
||||
{
|
||||
case FOURCC('D','X','T','1'):
|
||||
fmt = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
|
||||
break;
|
||||
case FOURCC('D','X','T','3'):
|
||||
fmt = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
break;
|
||||
case FOURCC('D','X','T','5'):
|
||||
fmt = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
break;
|
||||
}
|
||||
|
||||
tex->width = w;
|
||||
tex->height = h;
|
||||
tex->fmt = fmt;
|
||||
tex->bpp = 0;
|
||||
tex->s3tc_img_size = img_size;
|
||||
tex->ptr = img;
|
||||
|
||||
if(sizeof(DDSURFACEDESC2) != ddsd_size)
|
||||
err = "DDSURFACEDESC2 size mismatch";
|
||||
if(size < hdr_size + img_size)
|
||||
err = "not completely loaded";
|
||||
if(mipmaps > 0)
|
||||
err = "contains mipmaps";
|
||||
if(fmt == 0)
|
||||
err = "invalid pixel format (not DXT{1,3,5})";
|
||||
}
|
||||
|
||||
if(err)
|
||||
{
|
||||
printf("dds_load: %s: %s\n", fn, err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TGA
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef NO_TGA
|
||||
|
||||
static inline bool tga_valid(const u8* ptr, size_t size)
|
||||
{
|
||||
UNUSED(size)
|
||||
|
||||
// no color map; uncompressed grayscale or true color
|
||||
return (ptr[1] == 0 && (ptr[2] == 2 || ptr[2] == 3));
|
||||
}
|
||||
|
||||
|
||||
// requirements: uncompressed, direct color, bottom up
|
||||
static int tga_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
{
|
||||
const char* err = "";
|
||||
|
||||
const u8 img_id_len = ptr[0];
|
||||
const uint hdr_size = 18+img_id_len;
|
||||
if(size < hdr_size)
|
||||
err = "header not completely read";
|
||||
else
|
||||
{
|
||||
const u8 type = ptr[2];
|
||||
const u16 w = read_le16(ptr+12);
|
||||
const u16 h = read_le16(ptr+14);
|
||||
const u8 bpp = ptr[16];
|
||||
const u8 desc = ptr[17];
|
||||
|
||||
const u8 alpha_bits = desc & 0x0f;
|
||||
|
||||
const u8* img = ptr + hdr_size;
|
||||
const ulong img_size = (ulong)w * h * bpp / 8;
|
||||
|
||||
// determine format
|
||||
int fmt = -1;
|
||||
// .. grayscale
|
||||
if(type == 3)
|
||||
{
|
||||
if(bpp == 8)
|
||||
fmt = 0;
|
||||
else if(bpp == 16 && alpha_bits == 8)
|
||||
fmt = GL_LUMINANCE_ALPHA;
|
||||
}
|
||||
// .. true color
|
||||
else if(type == 2)
|
||||
{
|
||||
if(bpp == 24 && alpha_bits == 0)
|
||||
fmt = GL_BGR;
|
||||
else if(bpp == 32 && alpha_bits == 8)
|
||||
fmt = GL_BGRA;
|
||||
}
|
||||
|
||||
tex->width = w;
|
||||
tex->height = h;
|
||||
tex->fmt = fmt;
|
||||
tex->bpp = bpp;
|
||||
tex->ptr = img;
|
||||
|
||||
if(fmt == -1)
|
||||
err = "invalid format or bpp";
|
||||
if(desc & 0x18)
|
||||
err = "image is not bottom-up and left-to-right";
|
||||
if(size < hdr_size + img_size)
|
||||
err = "size < image size";
|
||||
}
|
||||
|
||||
if(err)
|
||||
{
|
||||
printf("tga_load: %s: %s\n", fn, err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// BMP
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef NO_BMP
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct BITMAPFILEHEADER
|
||||
{
|
||||
u16 bfType; // "BM"
|
||||
u32 bfSize; // of file
|
||||
u32 reserved;
|
||||
u32 bfOffBits; // offset to image data
|
||||
};
|
||||
|
||||
// BITMAPCOREHEADER + compression field
|
||||
struct BITMAPCOREHEADER2
|
||||
{
|
||||
u32 biSize;
|
||||
long biWidth;
|
||||
long biHeight;
|
||||
u16 biPlanes; // = 1
|
||||
u16 biBitCount; // bpp
|
||||
u32 biCompression;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#define BI_RGB 0 // bch->biCompression
|
||||
|
||||
|
||||
static inline bool bmp_valid(const u8* ptr, size_t size)
|
||||
{
|
||||
UNUSED(size)
|
||||
|
||||
// bfType == BM? (check single bytes => endian safe)
|
||||
return ptr[0] == 'B' && ptr[1] == 'M';
|
||||
}
|
||||
|
||||
|
||||
// requirements: uncompressed, direct color, bottom up
|
||||
static int bmp_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
{
|
||||
const char* err = 0;
|
||||
|
||||
BITMAPFILEHEADER* bfh = (BITMAPFILEHEADER*)ptr;
|
||||
BITMAPCOREHEADER2* bch = (BITMAPCOREHEADER2*)(ptr+sizeof(BITMAPFILEHEADER));
|
||||
const int hdr_size = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPCOREHEADER2);
|
||||
if(size < hdr_size)
|
||||
err = "header not completely read";
|
||||
else
|
||||
{
|
||||
const long w = read_le32(&bch->biWidth);
|
||||
const long h = read_le32(&bch->biHeight);
|
||||
const u16 bpp = read_le16(&bch->biBitCount);
|
||||
const u32 compress = read_le32(&bch->biCompression);
|
||||
const u32 ofs = read_le32(&bfh->bfOffBits);
|
||||
|
||||
const u8* img = ptr + ofs;
|
||||
const u32 img_size = w * h * bpp/8;
|
||||
|
||||
tex->width = w;
|
||||
tex->height = h;
|
||||
tex->fmt = (bpp == 24)? GL_BGR : GL_BGRA;
|
||||
tex->bpp = bpp;
|
||||
tex->ptr = img;
|
||||
|
||||
if(h < 0)
|
||||
err = "top-down";
|
||||
if(compress != BI_RGB)
|
||||
err = "compressed";
|
||||
if(bpp < 24)
|
||||
err = "not direct color";
|
||||
if(size < ofs+img_size)
|
||||
err = "image not completely read";
|
||||
}
|
||||
|
||||
if(err)
|
||||
{
|
||||
printf("bmp_load: %s: %s\n", fn, err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
// TODO: no extra buffer needed here; dealloc?
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RAW
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef NO_RAW
|
||||
|
||||
static inline bool raw_valid(const u8* p, size_t size)
|
||||
{
|
||||
UNUSED(p)
|
||||
UNUSED(size)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static int raw_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
{
|
||||
static GLenum fmts[5] = { 0, 0, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA };
|
||||
for(int i = 1; i <= 4; i++)
|
||||
{
|
||||
u32 dim = (u32)sqrtf((float)size/i);
|
||||
// TODO: differentiate 8/32 bpp
|
||||
if(dim*dim*i != size)
|
||||
continue;
|
||||
|
||||
tex->width = dim;
|
||||
tex->height = dim;
|
||||
tex->fmt = fmts[i];
|
||||
tex->bpp = i * 8;
|
||||
tex->ptr = ptr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("raw_load: %s: %s\n", fn, "no matching format found");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PNG
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef NO_PNG
|
||||
|
||||
struct MemRange
|
||||
{
|
||||
const u8* p;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
|
||||
static void png_read_fn(png_struct* png_ptr, u8* data, png_size_t length)
|
||||
{
|
||||
MemRange* const mr = (MemRange*)png_ptr->io_ptr;
|
||||
mr->size -= length;
|
||||
if(mr->size < 0)
|
||||
png_error(png_ptr, "png_read_fn: no data remaining");
|
||||
|
||||
memcpy(data, mr->ptr, length);
|
||||
mr->ptr += length;
|
||||
}
|
||||
|
||||
|
||||
static inline bool png_valid(const u8* ptr, size_t size)
|
||||
{
|
||||
return png_sig_cmp((u8*)ptr, 0, min(size, 8)) == 0;
|
||||
}
|
||||
|
||||
|
||||
// requirement: direct color
|
||||
static int png_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
{
|
||||
const char* err = 0;
|
||||
|
||||
// allocate PNG structures
|
||||
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
|
||||
if(!png_ptr)
|
||||
return -1;
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if(!info_ptr)
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, 0, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// setup error handling
|
||||
if(setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
fail:
|
||||
printf("png_load: %s: %s\n", fn, err? err : "");
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MemRange mr = { ptr, size };
|
||||
png_set_read_fn(png_ptr, &mr, png_read_fn);
|
||||
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
unsigned long width, height;
|
||||
int prec, color_type;
|
||||
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
|
||||
|
||||
// can only handle 8 bits per channel
|
||||
if(prec != 8)
|
||||
{
|
||||
err = "channel precision != 8";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// allocate mem for image - rows point into buffer (sequential)
|
||||
int pitch = png_get_rowbytes(png_ptr, info_ptr);
|
||||
u8* img = (u8*)malloc(pitch * (height+1));
|
||||
u8** rows = (u8**)png_malloc(png_ptr, (height+1)*sizeof(void*));
|
||||
for(u32 i = 0; i < height+1; i++)
|
||||
rows[i] = img + i*pitch;
|
||||
|
||||
png_read_image(png_ptr, rows);
|
||||
|
||||
png_read_end(png_ptr, 0);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
|
||||
|
||||
// store info in ti
|
||||
tex->width = width; tex->height = height;
|
||||
|
||||
int fmts[8] = { 0, -1, GL_RGB, -1, GL_LUMINANCE_ALPHA, -1, GL_RGBA, -1 };
|
||||
if(color_type >= 8)
|
||||
return -1;
|
||||
tex->fmt = fmts[color_type];
|
||||
if(tex->fmt == -1) // <==> palette image
|
||||
{
|
||||
printf("png_load: %s: %s\n", fn, "not direct color");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tex->ptr = img;
|
||||
tex->bpp = pitch / width * 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// JP2
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef NO_JP2
|
||||
|
||||
static inline bool jp2_valid(const u8* p, size_t size)
|
||||
{
|
||||
static bool initialized;
|
||||
if(!initialized)
|
||||
{
|
||||
jas_init();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
jas_stream_t* stream = jas_stream_memopen((char*)ptr, size);
|
||||
return jp2_validate(stream) >= 0;
|
||||
}
|
||||
|
||||
|
||||
static int jp2_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
|
||||
{
|
||||
const char* err = 0;
|
||||
|
||||
jas_stream_t* stream = jas_stream_memopen((char*)ptr, size);
|
||||
jas_image_t* image = jas_image_decode(stream, -1, 0);
|
||||
if(!image)
|
||||
return -1;
|
||||
|
||||
int num_cmpts = jas_image_numcmpts(image);
|
||||
jas_matrix_t* matr[4] = {0};
|
||||
jas_seqent_t* rows[4] = {0};
|
||||
int width = jas_image_cmptwidth (image, 0);
|
||||
int height = jas_image_cmptheight(image, 0);
|
||||
int prec = jas_image_cmptprec (image, 0);
|
||||
|
||||
if(depth != 8)
|
||||
{
|
||||
err = "channel precision != 8";
|
||||
printf("jp2_load: %s: %s\n", fn, err);
|
||||
// TODO: destroy image
|
||||
return -1;
|
||||
}
|
||||
|
||||
u8* img = (u8*)malloc(width*height*num_cmpts);
|
||||
u8* out = img;
|
||||
|
||||
int cmpt;
|
||||
for(cmpt = 0; cmpt < num_cmpts; cmpt++)
|
||||
matr[cmpt] = jas_matrix_create(1, width);
|
||||
|
||||
for(int y = 0; y < height; y++)
|
||||
{
|
||||
for(cmpt = 0; cmpt < num_cmpts; cmpt++)
|
||||
{
|
||||
jas_image_readcmpt(image, cmpt, 0, y, width, 1, matr[cmpt]);
|
||||
rows[cmpt] = jas_matrix_getref(matr[cmpt], 0, 0);
|
||||
}
|
||||
|
||||
for(int x = 0; x < width; x++)
|
||||
for(cmpt = 0; cmpt < num_cmpts; cmpt++)
|
||||
*out++ = *rows[cmpt]++;
|
||||
}
|
||||
|
||||
for(cmpt = 0; cmpt < num_cmpts; cmpt++)
|
||||
jas_matrix_destroy(matr[cmpt]);
|
||||
|
||||
tex->width = width;
|
||||
tex->height = height;
|
||||
tex->fmt = GL_RGB;
|
||||
tex->bpp = num_cmpts * 8;
|
||||
tex->ptr = img;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
static void tex_dtor(HDATA* hd)
|
||||
{
|
||||
TEX* tex = (TEX*)hd->internal;
|
||||
glDeleteTextures(1, &tex->id);
|
||||
}
|
||||
|
||||
|
||||
// TEX output param is invalid if function fails
|
||||
Handle tex_load(const char* fn, TEX* ptex)
|
||||
{
|
||||
// load file
|
||||
const u8* p;
|
||||
size_t size;
|
||||
HDATA* hd;
|
||||
Handle h = res_load(fn, RES_TEX, tex_dtor, (void*&)p, size, hd);
|
||||
if(!h)
|
||||
return 0;
|
||||
|
||||
TEX* tex = (TEX*)hd->internal;
|
||||
if(!p)
|
||||
goto already_loaded;
|
||||
if(size < 4) // guarantee xxx_valid routines 4 bytes
|
||||
return 0;
|
||||
|
||||
{
|
||||
int err = -1;
|
||||
|
||||
#ifndef NO_DDS
|
||||
if(dds_valid(p, size))
|
||||
err = dds_load(fn, p, size, tex); else
|
||||
#endif
|
||||
#ifndef NO_PNG
|
||||
if(png_valid(p, size))
|
||||
err = png_load(fn, p, size, tex); else
|
||||
#endif
|
||||
#ifndef NO_JP2
|
||||
if(jp2_valid(p, size))
|
||||
err = jp2_load(fn, p, size, tex); else
|
||||
#endif
|
||||
#ifndef NO_BMP
|
||||
if(bmp_valid(p, size))
|
||||
err = bmp_load(fn, p, size, tex); else
|
||||
#endif
|
||||
#ifndef NO_TGA
|
||||
if(tga_valid(p, size))
|
||||
err = tga_load(fn, p, size, tex); else
|
||||
#endif
|
||||
#ifndef NO_RAW
|
||||
if(raw_valid(p, size))
|
||||
err = raw_load(fn, p, size, tex); else
|
||||
#endif
|
||||
; // make sure else chain is ended
|
||||
|
||||
if(err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
// loaders weren't able to determine type
|
||||
if(tex->fmt == 0)
|
||||
{
|
||||
assert(tex->bpp == 8);
|
||||
tex->fmt = GL_ALPHA;
|
||||
// TODO: check file name, go to 32 bit if wrong
|
||||
}
|
||||
|
||||
{
|
||||
uint id;
|
||||
glGenTextures(1, &id);
|
||||
tex->id = id;
|
||||
}
|
||||
|
||||
already_loaded:
|
||||
if(ptex)
|
||||
*ptex = *tex;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
int tex_bind(const Handle h)
|
||||
{
|
||||
HDATA* hd = h_data(h, RES_TEX);
|
||||
if(!hd)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
return -1;
|
||||
}
|
||||
TEX* tex = (TEX*)hd->internal;
|
||||
glBindTexture(GL_TEXTURE_2D, tex->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tex_filter = GL_LINEAR;
|
||||
uint tex_bpp = 32; // 16 or 32
|
||||
|
||||
int tex_upload(const Handle h, int filter, int int_fmt)
|
||||
{
|
||||
HDATA* hd = h_data(h, RES_TEX);
|
||||
if(!hd)
|
||||
return -1;
|
||||
TEX* tex = (TEX*)hd->internal;
|
||||
|
||||
// greater than max supported tex dimension?
|
||||
// no-op if oglInit not yet called
|
||||
if(tex->width > (uint)max_tex_size || tex->height > (uint)max_tex_size)
|
||||
{
|
||||
assert(!"tex_upload: image dimensions exceed OpenGL implementation limit");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// both NV_texture_rectangle and subtexture require work for the client
|
||||
// (changing tex coords) => we'll just disallow non-power of 2 textures.
|
||||
// TODO: ARB_texture_non_power_of_two
|
||||
if(!is_pow2(tex->width) || !is_pow2(tex->height))
|
||||
{
|
||||
assert(!"tex_upload: image is not power-of-2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tex_bind(h);
|
||||
|
||||
// set filter
|
||||
if(!filter)
|
||||
filter = tex_filter;
|
||||
const int mag = (filter == GL_NEAREST)? GL_NEAREST : GL_LINEAR;
|
||||
const bool mipmap = (filter == GL_NEAREST_MIPMAP_NEAREST || filter == GL_LINEAR_MIPMAP_NEAREST ||
|
||||
filter == GL_NEAREST_MIPMAP_LINEAR || filter == GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag);
|
||||
|
||||
|
||||
const bool has_alpha = tex->fmt == GL_RGBA || tex->fmt == GL_BGRA || tex->fmt == GL_LUMINANCE_ALPHA || tex->fmt == GL_ALPHA;
|
||||
|
||||
// S3TC compressed
|
||||
if(tex->fmt >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT &&
|
||||
tex->fmt <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
|
||||
glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, tex->fmt, tex->width, tex->height, 0, tex->s3tc_img_size, tex->ptr);
|
||||
// normal
|
||||
else
|
||||
{
|
||||
// calc internal fmt from format and global bpp, if not passed as a param
|
||||
if(!int_fmt)
|
||||
{
|
||||
if(tex->bpp == 32)
|
||||
int_fmt = (tex_bpp == 32)? GL_RGBA8 : GL_RGBA4;
|
||||
else if(tex->bpp == 24)
|
||||
int_fmt = (tex_bpp == 32)? GL_RGB8 : GL_RGB5;
|
||||
else if(tex->bpp == 16)
|
||||
int_fmt = (tex_bpp == 32)? GL_LUMINANCE8_ALPHA8 : GL_LUMINANCE4_ALPHA4;
|
||||
else if(tex->fmt == GL_ALPHA)
|
||||
int_fmt = (tex_bpp == 32)? GL_ALPHA8 : GL_ALPHA4;
|
||||
else if(tex->fmt == GL_LUMINANCE)
|
||||
int_fmt = (tex_bpp == 32)? GL_LUMINANCE8 : GL_LUMINANCE4;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check if SGIS_generate_mipmap is available (once)
|
||||
static int sgm_avl = -1;
|
||||
if(sgm_avl == -1)
|
||||
sgm_avl = oglExtAvail("GL_SGIS_generate_mipmap");
|
||||
|
||||
// manual mipmap gen via GLU (box filter)
|
||||
if(mipmap && !sgm_avl)
|
||||
gluBuild2DMipmaps(GL_TEXTURE_2D, int_fmt, tex->width, tex->height, tex->fmt, GL_UNSIGNED_BYTE, tex->ptr);
|
||||
// auto mipmap gen, or no mipmap
|
||||
else
|
||||
{
|
||||
if(mipmap)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, tex->width, tex->height, 0, tex->fmt, GL_UNSIGNED_BYTE, tex->ptr);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
53
source/lib/tex.h
Executable file
53
source/lib/tex.h
Executable file
@ -0,0 +1,53 @@
|
||||
// OpenGL texturing
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#ifndef __TEX_H__
|
||||
#define __TEX_H__
|
||||
|
||||
#include "types.h"
|
||||
#include "res.h"
|
||||
|
||||
|
||||
struct TEX
|
||||
{
|
||||
u32 width : 16;
|
||||
u32 height : 16;
|
||||
u32 fmt : 16;
|
||||
u32 bpp : 8; // 0 if S3TC
|
||||
u32 s3tc_img_size;
|
||||
const u8* ptr;
|
||||
uint id;
|
||||
};
|
||||
|
||||
|
||||
// load and return a handle to the texture given in <fn>.
|
||||
// supports RAW, BMP, JP2, PNG, TGA, DDS
|
||||
// optionally returns a copy of information about the texture.
|
||||
extern Handle tex_load(const char* fn, TEX* tex_info = 0);
|
||||
|
||||
extern int tex_bind(Handle h);
|
||||
|
||||
|
||||
extern int tex_filter; // GL values; default: GL_LINEAR
|
||||
extern uint tex_bpp; // 16 or 32; default: 32
|
||||
|
||||
// upload the specified texture to OpenGL. Texture filter and internal format
|
||||
// may be specified to override the global defaults.
|
||||
extern int tex_upload(Handle h, int filter_override = 0, int internal_fmt_override = 0);
|
||||
|
||||
#endif // __TEX_H__
|
171
source/lib/time.cpp
Executable file
171
source/lib/time.cpp
Executable file
@ -0,0 +1,171 @@
|
||||
// platform indepentend high resolution timer
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#include <time.h>
|
||||
#include <cmath>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "win.h"
|
||||
#endif
|
||||
|
||||
#include "ia32.h"
|
||||
#include "posix.h"
|
||||
#include "detect.h"
|
||||
#include "time.h"
|
||||
#include "types.h"
|
||||
#include "misc.h"
|
||||
|
||||
|
||||
// high resolution (> 1 µs) timestamp [s], starting at or near 0 s.
|
||||
//
|
||||
// uses TSC on single processor x86 desktop systems unless NO_TSC is defined,
|
||||
// otherwise platform specific timers (QueryPerformanceCounter, gettimeofday).
|
||||
double get_time()
|
||||
{
|
||||
static double to_s;
|
||||
double t;
|
||||
|
||||
#if defined(_M_IX86) && !defined(NO_TSC)
|
||||
static int use_tsc = -1;
|
||||
static u64 tsc_start;
|
||||
|
||||
// spaghetti code for minimum timing overhead
|
||||
first_tsc:
|
||||
if(use_tsc == 1)
|
||||
return (__int64)(rdtsc() - tsc_start) * to_s;
|
||||
// VC6 can't convert u64 -> double; we don't need full range anyway
|
||||
// don't know yet
|
||||
if(use_tsc == -1)
|
||||
// don't use yet - need a time reference for CPU freq calculation.
|
||||
if(cpu_freq != 0.0f)
|
||||
// use only on single processor desktop systems
|
||||
// (otherwise CPU freq may change, clocks may get out of sync)
|
||||
if(cpus == 1 && !is_notebook && (cpu_caps & TSC))
|
||||
{
|
||||
use_tsc = 1;
|
||||
to_s = 1.0 / cpu_freq;
|
||||
tsc_start = rdtsc();
|
||||
goto first_tsc; // using the other timers now would trash to_s
|
||||
}
|
||||
else
|
||||
use_tsc = 0;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static LARGE_INTEGER start;
|
||||
LARGE_INTEGER i;
|
||||
|
||||
if(!to_s)
|
||||
{
|
||||
QueryPerformanceFrequency(&i);
|
||||
to_s = 1.0 / i.QuadPart;
|
||||
|
||||
QueryPerformanceCounter(&start);
|
||||
}
|
||||
|
||||
QueryPerformanceCounter(&i);
|
||||
t = (i.QuadPart - start.QuadPart) * to_s;
|
||||
|
||||
#else
|
||||
|
||||
static struct timeval start;
|
||||
struct timeval tv;
|
||||
|
||||
if(!start.tv_sec)
|
||||
gettimeofday(&start, 0);
|
||||
|
||||
gettimeofday(&tv, 0);
|
||||
t = (tv.tv_sec - start.tv_sec) + (tv.tv_usec - start.tv_usec)*1e-6;
|
||||
|
||||
#endif
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// calculate fps (call once per frame)
|
||||
// several smooth filters:
|
||||
// - throw out single spikes / dips
|
||||
// - average via small history buffer
|
||||
// - update final value iff the difference (% or absolute) is too great,
|
||||
// or if the change is consistent with the trend over the last few frames.
|
||||
//
|
||||
// => less fluctuation, but rapid tracking.
|
||||
// filter values are tuned for 100 FPS.
|
||||
|
||||
int fps = 0;
|
||||
|
||||
void calc_fps()
|
||||
{
|
||||
// history buffer - smooth out slight variations
|
||||
#define H 10 // # buffer entries
|
||||
static float fps_sum = 0; // sum of last H frames' cur_fps
|
||||
static float fps_hist[H]; // last H frames' cur_fps
|
||||
// => don't need to re-average every time
|
||||
static uint head = 0; // oldest entry in fps_hist
|
||||
// must be unsigned, b/c we do (head-1)%H
|
||||
|
||||
// get elapsed time [s] since last frame; approximate current fps
|
||||
static double last_t;
|
||||
double t = get_time();
|
||||
float cur_fps = 30.0f; // start value => history converges faster
|
||||
if(last_t != 0.0)
|
||||
cur_fps = 1.0f / (float)(t-last_t); // = 1 / elapsed time
|
||||
last_t = t;
|
||||
|
||||
// calculate fps activity over 3 frames (used below to prevent fluctuation)
|
||||
// -1: decreasing, +1: increasing, 0: neither or fluctuating
|
||||
float h1 = fps_hist[(head-1)%H]; // last frame's cur_fps
|
||||
float h2 = fps_hist[(head-2)%H]; // 2nd most recent frame's cur_fps
|
||||
|
||||
int trend = 0;
|
||||
if(h2 > h1 && h1 > cur_fps) // decreasing
|
||||
trend = -1;
|
||||
else if(cur_fps < h1 && h1 < h2) // increasing
|
||||
trend = 1;
|
||||
|
||||
// ignore onetime skips in fps (probably page faults or similar)
|
||||
static int bad = 0; // bad > 0 <==> last value was skipped
|
||||
if(fabs(h1-cur_fps) > .05f*h1) // > 5% difference
|
||||
{
|
||||
// first 'bad' value: don't update fps_hist/fps; otherwise, reset bad
|
||||
if(!bad++)
|
||||
return;
|
||||
}
|
||||
else
|
||||
bad = 0;
|
||||
|
||||
// remove oldest cur_fps value in fps_hist from the sum
|
||||
// and add cur_fps; also insert cur_fps in fps_hist
|
||||
fps_sum -= fps_hist[head];
|
||||
fps_sum += (fps_hist[head] = cur_fps);
|
||||
head = (head+1)%H;
|
||||
|
||||
// update fps counter if update threshold is exceeded
|
||||
const float avg_fps = fps_sum / H;
|
||||
const float d_avg = avg_fps-fps;
|
||||
const float max_diff = fminf(5.f, 0.05f*fps);
|
||||
|
||||
if((trend > 0 && (avg_fps > fps || d_avg < -4.f)) || // going up, or large drop
|
||||
(trend < 0 && (avg_fps < fps || d_avg > 4.f)) || // going down, or large raise
|
||||
(fabs(d_avg) > max_diff)) // significant difference
|
||||
fps = (int)avg_fps;
|
||||
}
|
44
source/lib/time.h
Executable file
44
source/lib/time.h
Executable file
@ -0,0 +1,44 @@
|
||||
// platform indepentend high resolution timer
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#ifndef __TIME_H__
|
||||
#define __TIME_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// high resolution (> 1 µs) timestamp [s], starting at or near 0 s.
|
||||
extern double get_time();
|
||||
|
||||
|
||||
// calculate fps (call once per frame)
|
||||
// several smooth filters (tuned for ~100 FPS)
|
||||
// => less fluctuation, but rapid tracking
|
||||
|
||||
extern int fps;
|
||||
|
||||
extern void calc_fps();
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #ifndef __TIME_H__
|
18
source/lib/types.h
Executable file
18
source/lib/types.h
Executable file
@ -0,0 +1,18 @@
|
||||
#ifndef __TYPES_H__
|
||||
#define __TYPES_H__
|
||||
|
||||
// defines instead of typedefs so we can #undef conflicting decls
|
||||
|
||||
#define uint unsigned int
|
||||
#define ulong unsigned long
|
||||
|
||||
#define int8 signed char
|
||||
#define int16 short
|
||||
#define int32 long
|
||||
|
||||
#define u8 unsigned char
|
||||
#define u16 unsigned short
|
||||
#define u32 unsigned long // compatibility with Win32 DWORD
|
||||
#define u64 unsigned __int64
|
||||
|
||||
#endif // #ifndef __TYPES_H__
|
328
source/lib/unzip.cpp
Executable file
328
source/lib/unzip.cpp
Executable file
@ -0,0 +1,328 @@
|
||||
// ZIP archiving (on top of ZLib)
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include "unzip.h"
|
||||
#include "posix.h"
|
||||
#include "misc.h"
|
||||
#include "res.h"
|
||||
#include "mem.h"
|
||||
#include "vfs.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "zlib.lib")
|
||||
#endif
|
||||
|
||||
|
||||
static const char ecdr_id[] = "PK\5\6"; // End of Central Directory Header identifier
|
||||
static const char cdfh_id[] = "PK\1\2"; // Central File Header identifier
|
||||
static const char lfh_id[] = "PK\3\4"; // Local File Header identifier
|
||||
|
||||
|
||||
// RES_ZFILE handle
|
||||
// location and size of an archived file
|
||||
// no destructor
|
||||
struct ZFILE
|
||||
{
|
||||
u32 ofs;
|
||||
u32 csize; // bit 31 = compression method (1: deflate; 0: stored)
|
||||
u32 ucsize;
|
||||
};
|
||||
|
||||
|
||||
// RES_ZARCHIVE handle
|
||||
// information about a ZIP archive
|
||||
struct ZARCHIVE
|
||||
{
|
||||
Handle hf; // actual ZIP file (RES_VFILE)
|
||||
|
||||
// file lookup
|
||||
u32 num_files;
|
||||
u32* fn_hashs; // split for more efficient search
|
||||
ZFILE* files;
|
||||
u32 last_file; // index of last file we found (speed up lookups of sequential files)
|
||||
};
|
||||
|
||||
|
||||
static void zarchive_dtor(HDATA* hd)
|
||||
{
|
||||
ZARCHIVE* z = (ZARCHIVE*)hd->internal;
|
||||
|
||||
vfs_close(z->hf);
|
||||
z->hf = 0;
|
||||
}
|
||||
|
||||
|
||||
// open and return a handle to the zip archive indicated by <fn>
|
||||
Handle zopen(const char* const fn)
|
||||
{
|
||||
const u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
|
||||
// already loaded?
|
||||
HDATA* hd;
|
||||
Handle h = h_find(fn_hash, RES_ZFILE, &hd);
|
||||
if(h)
|
||||
return h;
|
||||
|
||||
// map the ZIP file
|
||||
Handle hf = vfs_map(fn);
|
||||
hd = h_data(hf, 0);
|
||||
if(!hd)
|
||||
return 0;
|
||||
const size_t size = hd->size;
|
||||
const u8* zfile = (const u8*)hd->p;
|
||||
|
||||
// find end of central dir record
|
||||
// by scanning last 66000 bytes of file for ecdr_id magic
|
||||
// (zip comment <= 65535 bytes, sizeof(ECDR) = 22, add some for safety)
|
||||
// if the zip file is < 66000 bytes, scan the whole file
|
||||
|
||||
size_t bytes_left = min(size, 66000);
|
||||
const u8* ecdr = zfile + size - bytes_left;
|
||||
|
||||
while(bytes_left-3 > 0)
|
||||
{
|
||||
if(*(u32*)ecdr == *(u32*)&ecdr_id)
|
||||
goto found_ecdr;
|
||||
|
||||
// check next 4 bytes (non aligned!!)
|
||||
ecdr++;
|
||||
bytes_left--;
|
||||
}
|
||||
|
||||
// reached EOF and still haven't found the ECDR identifier
|
||||
|
||||
fail:
|
||||
vfs_close(hf);
|
||||
return 0;
|
||||
|
||||
{
|
||||
found_ecdr:
|
||||
// read ECDR
|
||||
const u16 num_files = read_le16(ecdr+10);
|
||||
const u32 cd_ofs = read_le32(ecdr+16);
|
||||
|
||||
// memory for fn_hash and File arrays
|
||||
void* mem = mem_alloc(num_files * (4 + sizeof(ZFILE)), MEM_HEAP, 4*KB);
|
||||
if(!mem)
|
||||
goto fail;
|
||||
|
||||
h = h_alloc(fn_hash, RES_ZFILE, zarchive_dtor, &hd);
|
||||
if(!h)
|
||||
goto fail;
|
||||
|
||||
ZARCHIVE* const za = (ZARCHIVE*)hd->internal;
|
||||
za->hf = hf;
|
||||
za->fn_hashs = (u32*)mem;
|
||||
za->files = (ZFILE*)((u8*)mem + 4*num_files);
|
||||
za->last_file = 0;
|
||||
|
||||
// cache file list for faster lookups
|
||||
// currently linear search, comparing filename hash.
|
||||
// TODO: if too slow, use hash table.
|
||||
const u8* cdfh = zfile+cd_ofs;
|
||||
u32* hs = za->fn_hashs;
|
||||
ZFILE* f = za->files;
|
||||
uint i;
|
||||
for(i = 0; i < num_files; i++)
|
||||
{
|
||||
// read CDFH
|
||||
if(*(u32*)cdfh != *(u32*)cdfh_id)
|
||||
continue;
|
||||
const u32 csize = read_le32(cdfh+20);
|
||||
const u32 ucsize = read_le32(cdfh+24);
|
||||
const u16 fn_len = read_le16(cdfh+28);
|
||||
const u16 e_len = read_le16(cdfh+30);
|
||||
const u16 c_len = read_le16(cdfh+32);
|
||||
const u32 lfh_ofs = read_le32(cdfh+42);
|
||||
const u8 method = cdfh[10];
|
||||
|
||||
if(method & ~8) // neither deflated nor stored
|
||||
continue;
|
||||
|
||||
// read LFH
|
||||
const u8* const lfh = zfile + lfh_ofs;
|
||||
if(*(u32*)lfh != *(u32*)lfh_id)
|
||||
continue;
|
||||
const u16 lfh_fn_len = read_le16(lfh+26);
|
||||
const u16 lfh_e_len = read_le16(lfh+28);
|
||||
const char* lfh_fn = (const char*)lfh+30;
|
||||
|
||||
*hs++ = fnv_hash(lfh_fn, lfh_fn_len);
|
||||
f->ofs = lfh_ofs + 30 + lfh_fn_len + lfh_e_len;
|
||||
f->csize = csize;
|
||||
f->ucsize = ucsize;
|
||||
f++;
|
||||
|
||||
(int&)cdfh += 46 + fn_len + e_len + c_len;
|
||||
}
|
||||
|
||||
za->num_files = i;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
void zclose(const Handle h)
|
||||
{
|
||||
if(h_data(h, RES_ZFILE))
|
||||
h_free(h, RES_ZFILE);
|
||||
else
|
||||
h_free(h, RES_ZARCHIVE);
|
||||
}
|
||||
|
||||
|
||||
Handle zopen(Handle hz, const char* fn)
|
||||
{
|
||||
HDATA* hzd = h_data(hz, RES_ZFILE);
|
||||
if(!hzd)
|
||||
return 0;
|
||||
ZARCHIVE* za = (ZARCHIVE*)hzd->internal;
|
||||
|
||||
// find its File descriptor
|
||||
const u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
uint i = za->last_file+1;
|
||||
if(i >= za->num_files || za->fn_hashs[i] != fn_hash)
|
||||
{
|
||||
for(i = 0; i < za->num_files; i++)
|
||||
if(za->fn_hashs[i] == fn_hash)
|
||||
break;
|
||||
if(i == za->num_files)
|
||||
return 0;
|
||||
|
||||
za->last_file = i;
|
||||
}
|
||||
const ZFILE* const f = &za->files[i];
|
||||
|
||||
//
|
||||
HDATA* hfd;
|
||||
Handle hf = h_alloc(fn_hash, RES_ZFILE, 0, &hfd);
|
||||
return hf;
|
||||
}
|
||||
|
||||
|
||||
int zread(Handle hf, void*& p, size_t& size, size_t ofs)
|
||||
{
|
||||
HDATA* hfd = h_data(hf, 0);
|
||||
if(!hfd)
|
||||
return -1;
|
||||
|
||||
ZFILE* zf = (ZFILE*)hfd->internal;
|
||||
const size_t ucsize = zf->ucsize;
|
||||
const size_t csize = zf->csize;
|
||||
|
||||
if(ofs > ucsize)
|
||||
return -1;
|
||||
|
||||
bool deflated = ucsize != csize;
|
||||
|
||||
// TODO: async read for uncompressed files?
|
||||
if(!deflated)
|
||||
{
|
||||
p = (u8*)hfd->p + zf->ofs + ofs;
|
||||
size = hfd->size - ofs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// double-buffered
|
||||
u32 slots[2];
|
||||
int active_read = 0;
|
||||
void* out_pos = 0;
|
||||
|
||||
void* out_mem = mem_alloc(ucsize, MEM_HEAP, 64*KB);
|
||||
if(!out_mem)
|
||||
return -1;
|
||||
|
||||
// inflating
|
||||
z_stream stream;
|
||||
if(deflated)
|
||||
{
|
||||
memset(&stream, 0, sizeof(stream));
|
||||
if(inflateInit2(&stream, -MAX_WBITS) != Z_OK)
|
||||
return -1;
|
||||
// -MAX_WBITS indicates no zlib header present
|
||||
|
||||
stream.next_out = (u8*)out_mem;
|
||||
stream.avail_out = ucsize;
|
||||
}
|
||||
// read directly into output buffer
|
||||
else
|
||||
out_pos = out_mem;
|
||||
|
||||
bool first = true;
|
||||
bool done = false;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// start reading next block
|
||||
if(!done)
|
||||
slots[active_read] = vfs_start_read(hf, ofs, &out_pos);
|
||||
|
||||
active_read ^= 1;
|
||||
|
||||
// process block read in previous iteration
|
||||
if(!first)
|
||||
{
|
||||
void* p;
|
||||
size_t bytes_read;
|
||||
vfs_finish_read(slots[active_read], p, bytes_read);
|
||||
|
||||
// inflate what we read
|
||||
if(deflated)
|
||||
{
|
||||
stream.next_in = (u8*)p;
|
||||
stream.avail_in = bytes_read;
|
||||
inflate(&stream, 0);
|
||||
}
|
||||
}
|
||||
|
||||
first = false;
|
||||
// one more iteration to process the last pending block
|
||||
if(done)
|
||||
break;
|
||||
if(ofs >= csize)
|
||||
done = true;
|
||||
}
|
||||
|
||||
if(deflated)
|
||||
{
|
||||
inflateEnd(&stream);
|
||||
|
||||
if(stream.total_in != csize || stream.total_out != ucsize)
|
||||
{
|
||||
mem_free(out_mem);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
p = out_mem;
|
||||
size = ucsize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//1 cache per zip - res layer doesnt know our internals (cache entry=ofs, csize,ucsize)
|
||||
//cache=array (allow finding next file quickly; need some mechanism for faster random access?)
|
||||
//sync is not a problem - zip file won't be updated during gameplay because it's still open
|
36
source/lib/unzip.h
Executable file
36
source/lib/unzip.h
Executable file
@ -0,0 +1,36 @@
|
||||
// ZIP archiving (on top of ZLib)
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#ifndef __UNZIP_H__
|
||||
#define __UNZIP_H__
|
||||
|
||||
|
||||
#include "res.h"
|
||||
|
||||
// open and return a handle to the zip archive indicated by <fn>
|
||||
extern Handle zopen(const char* fn);
|
||||
|
||||
// open and return a handle to file <fn> in the zip archive <hz>
|
||||
extern Handle zopen(Handle hz, const char* fn);
|
||||
|
||||
extern void zclose(Handle hz);
|
||||
|
||||
extern int zread(Handle hf, void*& p, size_t& size, size_t ofs);
|
||||
|
||||
|
||||
#endif // #ifndef __UNZIP_H__
|
351
source/lib/vfs.cpp
Executable file
351
source/lib/vfs.cpp
Executable file
@ -0,0 +1,351 @@
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "posix.h"
|
||||
#include "unzip.h"
|
||||
#include "misc.h"
|
||||
#include "vfs.h"
|
||||
#include "mem.h"
|
||||
|
||||
|
||||
// We need to be able to unmount specific paths (e.g. when switching mods).
|
||||
// Don't want to remount everything (slow), or specify a mod tag when mounting
|
||||
// (not this module's job). Instead, we include all archives in one path entry;
|
||||
// the game keeps track of what paths it mounted for a mod, and unmounts those
|
||||
// when needed.
|
||||
|
||||
struct PATH
|
||||
{
|
||||
char* dir; // relative to root; points to space at end of this struct
|
||||
struct PATH* next;
|
||||
int num_archives;
|
||||
Handle archives[1];
|
||||
// space allocated here for archive Handles + dir string
|
||||
};
|
||||
static PATH* path_list;
|
||||
|
||||
|
||||
static void vfile_dtor(HDATA* hd)
|
||||
{
|
||||
VFILE* vf = (VFILE*)hd->internal;
|
||||
|
||||
// normal file
|
||||
if(vf->fd != -1)
|
||||
{
|
||||
munmap(hd->p, hd->size);
|
||||
hd->p = 0;
|
||||
hd->size = 0;
|
||||
|
||||
close(vf->fd);
|
||||
vf->fd = -1;
|
||||
}
|
||||
|
||||
// in archive
|
||||
if(vf->ha && vf->hz)
|
||||
{
|
||||
zclose(vf->hz);
|
||||
zclose(vf->ha);
|
||||
vf->ha = vf->hz = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int vfs_set_root(const char* argv0, const char* root)
|
||||
{
|
||||
if(access(argv0, X_OK) != 0)
|
||||
return -1;
|
||||
|
||||
char path[PATH_MAX+1];
|
||||
path[PATH_MAX] = 0;
|
||||
if(!realpath(argv0, path))
|
||||
return -1;
|
||||
|
||||
// remove executable name
|
||||
char* fn = strrchr(path, DIR_SEP);
|
||||
if(!fn)
|
||||
return -1;
|
||||
*fn = 0;
|
||||
|
||||
chdir(path);
|
||||
chdir(root);
|
||||
|
||||
return vfs_mount(".");
|
||||
}
|
||||
|
||||
|
||||
int vfs_mount(const char* path)
|
||||
{
|
||||
const size_t path_len = strlen(path);
|
||||
if(path_len > VFS_MAX_PATH)
|
||||
{
|
||||
assert(!"vfs_mount_dir: path name is longer than VFS_MAX_PATH");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// enumerate all archives in <path>
|
||||
std::vector<std::string> archives;
|
||||
DIR* dir = opendir(path);
|
||||
struct dirent* ent;
|
||||
while((ent = readdir(dir)))
|
||||
{
|
||||
struct stat s;
|
||||
if(stat(ent->d_name, &s) < 0)
|
||||
continue;
|
||||
if(s.st_mode == S_IFREG) // regular file
|
||||
archives.push_back(ent->d_name);
|
||||
}
|
||||
closedir(dir);
|
||||
const int num_archives = archives.size();
|
||||
|
||||
// alloc search path entry (add to front)
|
||||
const int archives_size = num_archives*sizeof(Handle);
|
||||
const int entry_size = round_up(sizeof(PATH)+archives_size+path_len+1, 8);
|
||||
PATH* entry = (PATH*)mem_alloc(entry_size);
|
||||
if(!entry)
|
||||
return -1;
|
||||
entry->next = path_list;
|
||||
path_list = entry;
|
||||
|
||||
entry->dir = (char*)&entry->archives[0] + archives_size;
|
||||
strcpy(entry->dir, path);
|
||||
|
||||
// add archives in alphabetical order
|
||||
std::sort(archives.begin(), archives.end());
|
||||
entry->num_archives = num_archives;
|
||||
for(int i = 0; i < num_archives; i++)
|
||||
entry->archives[i] = zopen(archives[i].c_str());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int vfs_umount(const char* path)
|
||||
{
|
||||
PATH** prev = &path_list;
|
||||
PATH* entry = path_list;
|
||||
while(entry)
|
||||
{
|
||||
// found
|
||||
if(!strcmp(entry->dir, path))
|
||||
{
|
||||
// close all archives
|
||||
for(int i = 0; i < entry->num_archives; i++)
|
||||
zclose(entry->archives[i]);
|
||||
|
||||
// remove from list
|
||||
*prev = entry->next;
|
||||
mem_free(entry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
prev = &entry->next;
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
// not found
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
Handle vfs_map(const char* fn)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
if(stat(fn, &stat_buf) != 0)
|
||||
return 0;
|
||||
size_t size = stat_buf.st_size;
|
||||
|
||||
int fd = open(fn, O_RDONLY);
|
||||
if(fd < 0)
|
||||
return 0;
|
||||
|
||||
u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
|
||||
void* p = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
close(fd);
|
||||
if(p != MAP_FAILED)
|
||||
{
|
||||
HDATA* hd;
|
||||
Handle h = h_alloc(0, 0, vfile_dtor, &hd);
|
||||
if(h)
|
||||
{
|
||||
hd->p = p;
|
||||
hd->size = size;
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Handle vfs_open(const char* fn)
|
||||
{
|
||||
char buf[PATH_MAX+1]; buf[PATH_MAX] = 0;
|
||||
|
||||
// for each search path:
|
||||
for(PATH* entry = path_list; entry; entry = entry->next)
|
||||
{
|
||||
// dir
|
||||
const char* path = fn;
|
||||
if(entry->dir[0] != '.' || entry->dir[1] != '\0')
|
||||
{
|
||||
// only prepend dir if not "." (root) - "./" isn't portable
|
||||
snprintf(buf, PATH_MAX, "%s/%s", entry->dir, fn);
|
||||
path = buf;
|
||||
}
|
||||
Handle h = vfs_map(path);
|
||||
if(h)
|
||||
return h;
|
||||
|
||||
// archive
|
||||
for(int i = 0; i < entry->num_archives; i++)
|
||||
{
|
||||
Handle h = zopen(entry->archives[i], fn);
|
||||
if(h)
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
// not found
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const uint IDX_BITS = 4;
|
||||
const uint NUM_SLOTS = 1ul << IDX_BITS;
|
||||
const uint TAG_BITS = 32 - IDX_BITS;
|
||||
static struct Slot
|
||||
{
|
||||
u32 tag; // = 0 <==> slot available
|
||||
struct aiocb cb;
|
||||
}
|
||||
slots[NUM_SLOTS];
|
||||
|
||||
u32 vfs_start_read(const Handle hf, size_t& ofs, void** buf)
|
||||
{
|
||||
HDATA* hfd = h_data(hf, 0);
|
||||
if(!hfd)
|
||||
return -1;
|
||||
VFILE* vf = (VFILE*)hfd->internal;
|
||||
|
||||
ssize_t bytes_left = hfd->size - ofs;
|
||||
if(bytes_left < 0)
|
||||
return -1;
|
||||
|
||||
// TODO: thread safety
|
||||
|
||||
// find a free slot
|
||||
int i = 0;
|
||||
Slot* s = slots;
|
||||
for(; i < NUM_SLOTS; i++, s++)
|
||||
if(!s->tag)
|
||||
break;
|
||||
if(i == NUM_SLOTS)
|
||||
{
|
||||
assert(!"vfs_start_read: too many active reads; increase NUM_SLOTS");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// mark it in use
|
||||
static u32 tag;
|
||||
if(++tag == 1ul << TAG_BITS)
|
||||
{
|
||||
assert(!"vfs_start_read: tag overflow!");
|
||||
tag = 1;
|
||||
}
|
||||
s->tag = tag;
|
||||
|
||||
struct aiocb* cb = &s->cb;
|
||||
|
||||
// use the buffer given (e.g. read directly into output buffer)
|
||||
if(buf)
|
||||
cb->aio_buf = buf;
|
||||
// allocate our own (reused for subsequent requests)
|
||||
else
|
||||
if(!cb->aio_buf)
|
||||
{
|
||||
cb->aio_buf = mem_alloc(64*KB, MEM_HEAP, 64*KB);
|
||||
if(!cb->aio_buf)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// align to 64 KB for speed
|
||||
u32 rsize = min(64*KB - (ofs & 0xffff), bytes_left);
|
||||
|
||||
cb->aio_offset = ofs;
|
||||
cb->aio_nbytes = rsize;
|
||||
aio_read(cb);
|
||||
|
||||
ofs += rsize;
|
||||
if(buf)
|
||||
(int&)*buf += rsize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int vfs_finish_read(const u32 slot, void*& p, size_t& size)
|
||||
{
|
||||
p = 0;
|
||||
size = 0;
|
||||
|
||||
const uint idx = slot & (NUM_SLOTS-1);
|
||||
const u32 tag = slot >> IDX_BITS;
|
||||
Slot* const s = &slots[idx];
|
||||
if(s->tag != tag)
|
||||
{
|
||||
assert(!"vfs_finish_read: invalid slot");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct aiocb* cb = &s->cb;
|
||||
|
||||
// wait for read to complete
|
||||
while(aio_error(cb) == -EINPROGRESS)
|
||||
aio_suspend(&cb, 1, 0);
|
||||
|
||||
ssize_t bytes_read = aio_return(cb);
|
||||
|
||||
s->tag = 0; // free this slot
|
||||
|
||||
p = cb->aio_buf;
|
||||
size = bytes_read;
|
||||
|
||||
return (bytes_read > 0)? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int vfs_read(Handle h, void*& p, size_t& size, size_t ofs)
|
||||
{
|
||||
p = 0;
|
||||
size = 0;
|
||||
|
||||
HDATA* hd = h_data(h, RES_VFILE);
|
||||
if(hd)
|
||||
{
|
||||
if(ofs+size > hd->size)
|
||||
return -1;
|
||||
p = (u8*)hd->p + ofs;
|
||||
if(!size)
|
||||
size = hd->size - ofs;
|
||||
return 0;
|
||||
}
|
||||
// RES_ZFILE
|
||||
else
|
||||
return zread(h, p, size, ofs);
|
||||
}
|
||||
|
||||
|
||||
int vfs_close(Handle h)
|
||||
{
|
||||
h_free(h, 0);
|
||||
return 0;
|
||||
}
|
25
source/lib/vfs.h
Executable file
25
source/lib/vfs.h
Executable file
@ -0,0 +1,25 @@
|
||||
struct VFILE
|
||||
{
|
||||
int fd;
|
||||
|
||||
Handle hz; // position within archive (ZFILE)
|
||||
Handle ha; // archive (ZARCHIVE)
|
||||
};
|
||||
|
||||
#define VFS_MAX_PATH 40
|
||||
|
||||
extern int vfs_set_root(const char* argv0, const char* root);
|
||||
extern int vfs_mount(const char* path);
|
||||
extern int vfs_umount(const char* path);
|
||||
|
||||
extern Handle vfs_map(const char* fn); // actual path in real FS
|
||||
|
||||
extern Handle vfs_open(const char* fn);
|
||||
extern int vfs_close(Handle h);
|
||||
|
||||
// size: in - maximum byte count
|
||||
// out - bytes actually read
|
||||
extern int vfs_read(Handle h, void*& p, size_t& size, size_t ofs = 0);
|
||||
|
||||
extern u32 vfs_start_read(Handle hf, size_t& ofs, void** buf = 0);
|
||||
extern int vfs_finish_read(u32 slot, void*& p, size_t& size);
|
78
source/lib/win.h
Executable file
78
source/lib/win.h
Executable file
@ -0,0 +1,78 @@
|
||||
// sockets already defined by posix.h
|
||||
#ifdef __POSIX_H__
|
||||
#define _WINSOCKAPI_
|
||||
#endif
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define VC_EXTRALEAN
|
||||
|
||||
// set version; needed for EnumDisplayDevices
|
||||
#define _WIN32_WINNT 0x0500
|
||||
|
||||
|
||||
#define NOGDICAPMASKS // CC_*, LC_*, PC_*, CP_*, TC_*, RC_
|
||||
//#define NOVIRTUALKEYCODES // VK_*
|
||||
//#define NOWINMESSAGES // WM_*, EM_*, LB_*, CB_*
|
||||
//#define NOWINSTYLES // WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
|
||||
#define NOSYSMETRICS // SM_*
|
||||
#define NOMENUS // MF_*
|
||||
#define NOICONS // IDI_*
|
||||
#define NOKEYSTATES // MK_*
|
||||
//#define NOSYSCOMMANDS // SC_*
|
||||
#define NORASTEROPS // Binary and Tertiary raster ops
|
||||
//#define NOSHOWWINDOW // SW_*
|
||||
#define OEMRESOURCE // OEM Resource values
|
||||
#define NOATOM // Atom Manager routines
|
||||
//#define NOCLIPBOARD // Clipboard routines
|
||||
#define NOCOLOR // Screen colors
|
||||
#define NOCTLMGR // Control and Dialog routines
|
||||
#define NODRAWTEXT // DrawText() and DT_*
|
||||
//#define NOGDI // All GDI defines and routines
|
||||
//#define NOKERNEL // All KERNEL defines and routines
|
||||
//#define NOUSER // All USER defines and routines
|
||||
#define NONLS // All NLS defines and routines
|
||||
//#define NOMB // MB_* and MessageBox()
|
||||
#define NOMEMMGR // GMEM_*, LMEM_*, GHND, LHND, associated routines
|
||||
#define NOMETAFILE // typedef METAFILEPICT
|
||||
#define NOMINMAX // Macros min(a,b) and max(a,b)
|
||||
//#define NOMSG // typedef MSG and associated routines
|
||||
#define NOOPENFILE // OpenFile(), OemToAnsi, AnsiToOem, and OF_*
|
||||
#define NOSCROLL // SB_* and scrolling routines
|
||||
#define NOSERVICE // All Service Controller routines, SERVICE_ equates, etc.
|
||||
//#define NOSOUND // Sound driver routines
|
||||
#define NOTEXTMETRIC // typedef TEXTMETRIC and associated routines
|
||||
//#define NOWH // SetWindowsHook and WH_*
|
||||
#define NOWINOFFSETS // GWL_*, GCL_*, associated routines
|
||||
//#define NOCOMM // COMM driver routines
|
||||
#define NOKANJI // Kanji support stuff.
|
||||
#define NOHELP // Help engine interface.
|
||||
#define NOPROFILER // Profiler interface.
|
||||
#define NODEFERWINDOWPOS // DeferWindowPos routines
|
||||
#define NOMCX // Modem Configuration Extensions
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// VC6 windows.h may not have defined these
|
||||
#ifndef INVALID_FILE_ATTRIBUTES
|
||||
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
|
||||
#endif
|
||||
#ifndef PROCESSOR_ARCHITECTURE_AMD64
|
||||
#define PROCESSOR_ARCHITECTURE_AMD64 9
|
||||
#endif
|
||||
|
||||
// HACK: warning-free definition for ICC (value is -1)
|
||||
#undef INVALID_HANDLE_VALUE
|
||||
const HANDLE INVALID_HANDLE_VALUE = (HANDLE)(((char*)0) + ~0);
|
||||
|
||||
extern "C" {
|
||||
extern int _get_osfhandle(int);
|
||||
extern int _open(const char* fn, int mode, ...);
|
||||
extern int _close(int);
|
||||
|
||||
#ifndef NO_WINSOCK
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "wsock32.lib")
|
||||
#endif
|
||||
extern __declspec(dllimport) int __stdcall WSAStartup(WORD, char*);
|
||||
#endif
|
||||
}
|
554
source/lib/wsdl.cpp
Executable file
554
source/lib/wsdl.cpp
Executable file
@ -0,0 +1,554 @@
|
||||
/*
|
||||
* emulation of a subset of SDL and GLUT for Win32
|
||||
*
|
||||
* Copyright (c) 2003 Jan Wassenberg
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contact info:
|
||||
* Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
* http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <process.h>
|
||||
|
||||
#include "wsdl.h"
|
||||
#include "win.h"
|
||||
#include "misc.h"
|
||||
|
||||
|
||||
/* state */
|
||||
static bool app_active; /* is window active & on top?
|
||||
if not, msg loop should yield */
|
||||
static bool fullscreen; /* in fullscreen mode?
|
||||
if so, restore mode when app is deactivated */
|
||||
|
||||
HWND hWnd = 0; /* available to the app for ShowWindow calls, etc. */
|
||||
|
||||
static DEVMODE dm; /* current video mode */
|
||||
static HDC hDC;
|
||||
static HGLRC hGLRC;
|
||||
|
||||
static int z_depth = 24; /* depth buffer size; set via SDL_GL_SetAttribute */
|
||||
|
||||
static u16 mouse_x, mouse_y;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* shared msg handler
|
||||
* SDL and GLUT have separate pumps; messages are handled there
|
||||
*/
|
||||
static LRESULT CALLBACK wndproc(HWND hWnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_PAINT:
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(hWnd, &ps);
|
||||
EndPaint(hWnd, &ps);
|
||||
return 0;
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
return 0;
|
||||
|
||||
// prevent screensaver / monitor power off
|
||||
case WM_SYSCOMMAND:
|
||||
if(wParam == SC_SCREENSAVE || wParam == SC_MONITORPOWER)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case WM_ACTIVATE:
|
||||
app_active = (wParam & 0xffff) != 0;
|
||||
|
||||
if(fullscreen)
|
||||
{
|
||||
if(app_active)
|
||||
ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
|
||||
else
|
||||
ChangeDisplaySettings(0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_CLOSE:
|
||||
exit(0);
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
|
||||
int SDL_PollEvent(SDL_Event* ev)
|
||||
{
|
||||
if(!ev)
|
||||
return -1;
|
||||
|
||||
// events that trigger messages (mouse done below)
|
||||
MSG msg;
|
||||
while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
|
||||
int sdl_btn = -1;
|
||||
|
||||
switch(msg.message)
|
||||
{
|
||||
//
|
||||
case WM_KEYUP:
|
||||
case WM_KEYDOWN:
|
||||
ev->type = (u8)((msg.message == WM_KEYUP)? SDL_KEYUP : SDL_KEYDOWN);
|
||||
ev->key.keysym.sym = (SDLKey)msg.wParam;
|
||||
return 1;
|
||||
|
||||
//
|
||||
case WM_ACTIVATE:
|
||||
ev->type = SDL_ACTIVE;
|
||||
ev->active.gain = app_active;
|
||||
ev->active.state = 0;
|
||||
return 1;
|
||||
|
||||
//
|
||||
case WM_MOUSEWHEEL:
|
||||
sdl_btn = (msg.wParam & BIT(31))? SDL_BUTTON_WHEELUP : SDL_BUTTON_WHEELDOWN;
|
||||
break; // event filled in mouse code below
|
||||
}
|
||||
|
||||
// mouse button
|
||||
// map Win L(up,down,double),R(),M() to L,R,M with up flag
|
||||
uint btn = msg.message-0x201; // 0..8 if it's a valid button;
|
||||
if(btn < 9 && btn%3 != 2) // every third msg is dblclick
|
||||
sdl_btn = SDL_BUTTON_LEFT + btn/3; // assumes L,R,M
|
||||
if(sdl_btn != -1)
|
||||
{
|
||||
ev->type = SDL_MOUSEBUTTONDOWN + btn%3;
|
||||
ev->button.button = (u8)sdl_btn;
|
||||
ev->button.x = (u16)(msg.lParam & 0xffff);
|
||||
ev->button.y = (u16)((msg.lParam >> 16) & 0xffff);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// mouse motion
|
||||
//
|
||||
// don't use DirectInput, because we want to respect the user's mouse
|
||||
// sensitivity settings. Windows messages are laggy, so poll instead.
|
||||
POINT p;
|
||||
GetCursorPos(&p);
|
||||
if(mouse_x != p.x || mouse_y != p.y)
|
||||
{
|
||||
ev->type = SDL_MOUSEMOTION;
|
||||
ev->motion.x = mouse_x = (u16)p.x;
|
||||
ev->motion.y = mouse_y = (u16)p.y;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int SDL_GL_SetAttribute(SDL_GLattr attr, int value)
|
||||
{
|
||||
if(attr == SDL_GL_DEPTH_SIZE)
|
||||
z_depth = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* set video mode wxh:bpp if necessary.
|
||||
* w = h = bpp = 0 => no change.
|
||||
*/
|
||||
int SDL_SetVideoMode(int w, int h, int bpp, u32 flags)
|
||||
{
|
||||
fullscreen = (flags & SDL_FULLSCREEN);
|
||||
|
||||
/* get current mode settings */
|
||||
dm.dmSize = sizeof(DEVMODE);
|
||||
EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm);
|
||||
int cur_w = dm.dmPelsWidth, cur_h = dm.dmPelsHeight;
|
||||
|
||||
dm.dmBitsPerPel = bpp;
|
||||
dm.dmFields = DM_BITSPERPEL;
|
||||
|
||||
/*
|
||||
* check if mode needs to be changed
|
||||
* (could split this out, but depends on fullscreen and dm)
|
||||
*/
|
||||
if(w != 0 && h != 0 && bpp != 0)
|
||||
if(/* higher res mode needed */
|
||||
(w > cur_w || h > cur_h) ||
|
||||
/* fullscreen, and not exact mode */
|
||||
(fullscreen && (w != cur_w || h != cur_h)))
|
||||
{
|
||||
dm.dmPelsWidth = w;
|
||||
dm.dmPelsHeight = h;
|
||||
dm.dmFields |= DM_PELSWIDTH|DM_PELSHEIGHT;
|
||||
}
|
||||
// mode set at first WM_ACTIVATE
|
||||
|
||||
/*
|
||||
* window init
|
||||
* create new window every time (instead of once at startup), 'cause
|
||||
* pixel format isn't supposed to be changed more than once
|
||||
*/
|
||||
|
||||
HINSTANCE hInst = GetModuleHandle(0);
|
||||
|
||||
/* register window class */
|
||||
static WNDCLASS wc;
|
||||
wc.style = CS_OWNDC;
|
||||
wc.lpfnWndProc = wndproc;
|
||||
wc.lpszClassName = "ogl";
|
||||
wc.hInstance = hInst;
|
||||
RegisterClass(&wc);
|
||||
|
||||
hWnd = CreateWindowEx(0, "ogl", APP_NAME, WS_POPUP|WS_VISIBLE, 0, 0, w, h, 0, 0, hInst, 0);
|
||||
if(!hWnd)
|
||||
return 0;
|
||||
|
||||
hDC = GetDC(hWnd);
|
||||
|
||||
/* set pixel format */
|
||||
static PIXELFORMATDESCRIPTOR pfd =
|
||||
{
|
||||
sizeof(PIXELFORMATDESCRIPTOR),
|
||||
1,
|
||||
PFD_SUPPORT_OPENGL|PFD_DRAW_TO_WINDOW|PFD_DOUBLEBUFFER,
|
||||
PFD_TYPE_RGBA,
|
||||
(BYTE)bpp,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
(BYTE)z_depth,
|
||||
0, 0,
|
||||
PFD_MAIN_PLANE,
|
||||
0, 0, 0, 0
|
||||
};
|
||||
|
||||
int pf = ChoosePixelFormat(hDC, &pfd);
|
||||
if(!SetPixelFormat(hDC, pf, &pfd))
|
||||
return 0;
|
||||
|
||||
hGLRC = wglCreateContext(hDC);
|
||||
if(!hGLRC)
|
||||
return 0;
|
||||
|
||||
if(!wglMakeCurrent(hDC, hGLRC))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
inline void SDL_GL_SwapBuffers()
|
||||
{
|
||||
SwapBuffers(hDC);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void SDL_Quit()
|
||||
{
|
||||
DestroyWindow(hWnd);
|
||||
|
||||
wglMakeCurrent(0, 0);
|
||||
wglDeleteContext(hGLRC);
|
||||
ChangeDisplaySettings(0, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define DDRAW
|
||||
|
||||
|
||||
#ifdef DDRAW
|
||||
#include <ddraw.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "ddraw.lib")
|
||||
// for DirectDrawCreate. don't bother with dynamic linking -
|
||||
// DirectX is present in all Windows versions since Win95.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
SDL_VideoInfo* SDL_GetVideoInfo()
|
||||
{
|
||||
static SDL_VideoInfo video_info;
|
||||
|
||||
#ifdef DDRAW
|
||||
|
||||
static bool init;
|
||||
if(!init)
|
||||
{
|
||||
IDirectDraw* dd = 0;
|
||||
HRESULT hr = DirectDrawCreate(0, &dd, 0);
|
||||
if(SUCCEEDED(hr) && dd != 0)
|
||||
{
|
||||
static DDCAPS caps;
|
||||
caps.dwSize = sizeof(caps);
|
||||
hr = dd->GetCaps(&caps, 0);
|
||||
if(SUCCEEDED(hr))
|
||||
video_info.video_mem = caps.dwVidMemTotal;
|
||||
dd->Release();
|
||||
}
|
||||
|
||||
init = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return &video_info;
|
||||
}
|
||||
|
||||
|
||||
SDL_Surface* SDL_GetVideoSurface()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__declspec(naked) u32 SDL_GetTicks()
|
||||
{
|
||||
__asm jmp dword ptr [GetTickCount]
|
||||
}
|
||||
|
||||
|
||||
void* SDL_GL_GetProcAddress(const char* name)
|
||||
{
|
||||
return wglGetProcAddress(name);
|
||||
}
|
||||
|
||||
|
||||
SDL_sem* SDL_CreateSemaphore(int cnt)
|
||||
{
|
||||
return (SDL_sem*)CreateSemaphore(0, cnt, 0x7fffffff, 0);
|
||||
}
|
||||
|
||||
void __stdcall SDL_DestroySemaphore(SDL_sem*)
|
||||
{
|
||||
__asm jmp dword ptr [CloseHandle]
|
||||
}
|
||||
|
||||
int SDL_SemPost(SDL_sem* sem)
|
||||
{
|
||||
return ReleaseSemaphore(sem, 1, 0);
|
||||
}
|
||||
|
||||
int SDL_SemWait(SDL_sem* sem)
|
||||
{
|
||||
return WaitForSingleObject(sem, INFINITE);
|
||||
}
|
||||
|
||||
SDL_Thread* SDL_CreateThread(int(*func)(void*), void* param)
|
||||
{
|
||||
return (SDL_Thread*)_beginthread((void(*)(void*))func, 0, param);
|
||||
}
|
||||
|
||||
|
||||
int SDL_KillThread(SDL_Thread* thread)
|
||||
{
|
||||
return TerminateThread(thread, 0);
|
||||
}
|
||||
|
||||
|
||||
__declspec(naked) int __stdcall SDL_WarpMouse(int, int)
|
||||
{
|
||||
__asm jmp dword ptr [SetCursorPos]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static bool need_redisplay; /* display callback should be called in next main loop iteration */
|
||||
|
||||
|
||||
|
||||
/* glut callbacks */
|
||||
static void (*idle)();
|
||||
static void (*display)();
|
||||
static void (*key)(int, int, int);
|
||||
static void (*special)(int, int, int);
|
||||
static void (*mouse)(int, int, int, int);
|
||||
|
||||
void glutIdleFunc(void (*func)())
|
||||
{ idle = func; }
|
||||
|
||||
void glutDisplayFunc(void (*func)())
|
||||
{ display = func; }
|
||||
|
||||
void glutKeyboardFunc(void (*func)(int, int, int))
|
||||
{ key = func; }
|
||||
|
||||
void glutSpecialFunc(void (*func)(int, int, int))
|
||||
{ special = func; }
|
||||
|
||||
void glutMouseFunc(void (*func)(int, int, int, int))
|
||||
{ mouse = func; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void glutInit(int* argc, char* argv[])
|
||||
{
|
||||
UNUSED(argc)
|
||||
UNUSED(argv)
|
||||
|
||||
SDL_Init(0);
|
||||
atexit(SDL_Quit);
|
||||
}
|
||||
|
||||
|
||||
int glutGet(int arg)
|
||||
{
|
||||
if(arg == GLUT_ELAPSED_TIME)
|
||||
return GetTickCount();
|
||||
|
||||
dm.dmSize = sizeof(DEVMODE);
|
||||
EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm);
|
||||
|
||||
if(arg == GLUT_SCREEN_WIDTH)
|
||||
return dm.dmPelsWidth;
|
||||
if(arg == GLUT_SCREEN_HEIGHT)
|
||||
return dm.dmPelsHeight;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int w, h, bpp, refresh;
|
||||
|
||||
int glutGameModeString(const char* str)
|
||||
{
|
||||
/* default = "don't care", in case string doesn't specify all values */
|
||||
w = 0, h = 0, bpp = 0, refresh = 0;
|
||||
|
||||
sscanf(str, "%dx%d:%d@%d", &w, &h, &bpp, &refresh);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
int glutEnterGameMode()
|
||||
{
|
||||
return SDL_SetVideoMode(w, h, bpp, SDL_OPENGL|SDL_FULLSCREEN);
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline void glutPostRedisplay()
|
||||
{
|
||||
need_redisplay = true;
|
||||
}
|
||||
|
||||
|
||||
void glutSetCursor(int cursor)
|
||||
{
|
||||
SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(cursor)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* GLUT message handler
|
||||
* message also goes to the shared wndproc
|
||||
*
|
||||
* not done in wndproc to separate GLUT and SDL;
|
||||
* split out of glutMainLoop for clarity.
|
||||
*/
|
||||
static void glut_process_msg(MSG* msg)
|
||||
{
|
||||
switch(msg->message)
|
||||
{
|
||||
case WM_PAINT:
|
||||
need_redisplay = true;
|
||||
break;
|
||||
|
||||
case WM_CHAR:
|
||||
if(key)
|
||||
key((int)msg->wParam, mouse_x, mouse_y);
|
||||
break;
|
||||
|
||||
case WM_KEYDOWN:
|
||||
if(special)
|
||||
special((int)msg->wParam, mouse_x, mouse_y);
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN: /* FIXME: only left/right clicks, assume GLUT_LEFT|RIGHT_BUTTON == 0, 1 */
|
||||
if(mouse)
|
||||
mouse(msg->message == WM_RBUTTONDOWN, GLUT_DOWN, (int)(msg->lParam & 0xffff), (int)(msg->lParam >> 16));
|
||||
break;
|
||||
|
||||
case WM_MOUSEWHEEL:
|
||||
if(mouse)
|
||||
mouse(GLUT_MIDDLE_BUTTON, ((short)(msg->wParam >> 16) > 0)? GLUT_UP : GLUT_DOWN, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void glutMainLoop()
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if(!app_active)
|
||||
WaitMessage();
|
||||
|
||||
MSG msg;
|
||||
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
|
||||
{
|
||||
glut_process_msg(&msg);
|
||||
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
if(idle)
|
||||
idle();
|
||||
|
||||
if(need_redisplay)
|
||||
{
|
||||
need_redisplay = false;
|
||||
display();
|
||||
}
|
||||
}
|
||||
}
|
309
source/lib/wsdl.h
Executable file
309
source/lib/wsdl.h
Executable file
@ -0,0 +1,309 @@
|
||||
#ifndef _WIN32
|
||||
#include <SDL/SDL.h>
|
||||
#include <SDL/SDL_thread.h>
|
||||
#define __WSDL_H__ // => rest of header ignored
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef __WSDL_H__
|
||||
#define __WSDL_H__
|
||||
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/* allow apps to override window name */
|
||||
#ifndef APP_NAME
|
||||
#define APP_NAME "ogl"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* SDL_Init flags */
|
||||
#define SDL_INIT_VIDEO 0
|
||||
#define SDL_INIT_AUDIO 0
|
||||
#define SDL_INIT_TIMER 0
|
||||
#define SDL_INIT_NOPARACHUTE 0
|
||||
|
||||
extern void SDL_Quit();
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SDL_GL_DEPTH_SIZE,
|
||||
SDL_GL_DOUBLEBUFFER /* ignored - always double buffered */
|
||||
}
|
||||
SDL_GLattr;
|
||||
|
||||
extern int SDL_GL_SetAttribute(SDL_GLattr attr, int value);
|
||||
|
||||
|
||||
/* SDL_SetVideoMode() flags */
|
||||
#define SDL_OPENGL 0
|
||||
#define SDL_FULLSCREEN 1
|
||||
|
||||
extern int SDL_SetVideoMode(int w, int h, int bpp, u32 flags);
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int w, h;
|
||||
}
|
||||
SDL_Surface;
|
||||
|
||||
extern SDL_Surface* SDL_GetVideoSurface();
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int video_mem;
|
||||
}
|
||||
SDL_VideoInfo;
|
||||
|
||||
extern SDL_VideoInfo* SDL_GetVideoInfo();
|
||||
|
||||
|
||||
/*
|
||||
* threads / sync
|
||||
*/
|
||||
|
||||
typedef void SDL_sem;
|
||||
typedef void SDL_Thread;
|
||||
|
||||
extern void* SDL_GL_GetProcAddress(const char*);
|
||||
|
||||
extern void SDL_GL_SwapBuffers();
|
||||
|
||||
extern u32 SDL_GetTicks();
|
||||
|
||||
extern SDL_sem* SDL_CreateSemaphore(int cnt);
|
||||
extern void __stdcall SDL_DestroySemaphore(SDL_sem*);
|
||||
extern int SDL_SemPost(SDL_sem*);
|
||||
extern int SDL_SemWait(SDL_sem* sem);
|
||||
|
||||
extern SDL_Thread* SDL_CreateThread(int(*)(void*), void*);
|
||||
extern int SDL_KillThread(SDL_Thread*);
|
||||
|
||||
extern int __stdcall SDL_WarpMouse(int, int);
|
||||
|
||||
|
||||
|
||||
|
||||
/* macros */
|
||||
|
||||
#define SDL_Init
|
||||
|
||||
#define SDL_GRAB_ON 0
|
||||
#define SDL_WM_GrabInput(a)
|
||||
#define SDL_GetError() ""
|
||||
|
||||
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* events
|
||||
************************************************************************************************/
|
||||
|
||||
/* SDLKey (mapped to VK_* codes) */
|
||||
typedef enum
|
||||
{
|
||||
SDLK_ESCAPE = 0x1b,
|
||||
SDLK_8 = '8',
|
||||
SDLK_9 = '9',
|
||||
SDLK_0 = '0',
|
||||
SDLK_p = 'P',
|
||||
SDLK_r = 'R',
|
||||
SDLK_s = 'S',
|
||||
|
||||
SDLK_KP_ADD = 0x6b,
|
||||
SDLK_KP_MINUS = 0x6d,
|
||||
SDLK_LEFT = 0x25,
|
||||
SDLK_UP = 0x26,
|
||||
SDLK_RIGHT = 0x27,
|
||||
SDLK_DOWN = 0x28,
|
||||
|
||||
SDLK_KP0 = 0x60,
|
||||
SDLK_KP1 = 0x61,
|
||||
SDLK_KP2 = 0x62,
|
||||
SDLK_KP3 = 0x63,
|
||||
SDLK_KP4 = 0x64,
|
||||
SDLK_KP5 = 0x65,
|
||||
SDLK_KP6 = 0x66,
|
||||
SDLK_KP7 = 0x67,
|
||||
SDLK_KP8 = 0x68,
|
||||
SDLK_KP9 = 0x69,
|
||||
|
||||
__SDLK // hack to allow trailing comma
|
||||
}
|
||||
SDLKey;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SDLKey sym;
|
||||
}
|
||||
SDL_keysym;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SDL_keysym keysym;
|
||||
}
|
||||
SDL_KeyboardEvent;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16 x, y;
|
||||
}
|
||||
SDL_MouseMotionEvent;
|
||||
|
||||
/* SDL_MouseButtonEvent.button */
|
||||
enum
|
||||
{
|
||||
// do not change order
|
||||
SDL_BUTTON_LEFT,
|
||||
SDL_BUTTON_RIGHT,
|
||||
SDL_BUTTON_MIDDLE,
|
||||
|
||||
SDL_BUTTON_WHEELUP,
|
||||
SDL_BUTTON_WHEELDOWN
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 button;
|
||||
u8 state;
|
||||
u16 x, y;
|
||||
}
|
||||
SDL_MouseButtonEvent;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 gain;
|
||||
u8 state;
|
||||
}
|
||||
SDL_ActiveEvent;
|
||||
|
||||
/* SDL_Event.type */
|
||||
enum
|
||||
{
|
||||
SDL_KEYDOWN,
|
||||
SDL_KEYUP,
|
||||
SDL_MOUSEMOTION,
|
||||
SDL_MOUSEBUTTONDOWN,
|
||||
SDL_MOUSEBUTTONUP,
|
||||
SDL_ACTIVE
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 type;
|
||||
union
|
||||
{
|
||||
SDL_KeyboardEvent key;
|
||||
SDL_MouseMotionEvent motion;
|
||||
SDL_MouseButtonEvent button;
|
||||
SDL_ActiveEvent active;
|
||||
};
|
||||
}
|
||||
SDL_Event;
|
||||
|
||||
extern int SDL_PollEvent(SDL_Event* ev);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* glutInitDisplayMode */
|
||||
#define GLUT_RGB 0
|
||||
#define GLUT_DOUBLE 0
|
||||
#define GLUT_DEPTH 0
|
||||
|
||||
/* mouse buttons */
|
||||
enum
|
||||
{
|
||||
GLUT_LEFT_BUTTON,
|
||||
GLUT_RIGHT_BUTTON,
|
||||
GLUT_MIDDLE_BUTTON /* also wheel, if avail */
|
||||
};
|
||||
|
||||
/* mouse button state */
|
||||
enum
|
||||
{
|
||||
GLUT_DOWN,
|
||||
GLUT_UP
|
||||
};
|
||||
|
||||
/* keys */
|
||||
enum
|
||||
{
|
||||
GLUT_KEY_LEFT = 0x25, /* VK_* */
|
||||
GLUT_KEY_RIGHT = 0x27,
|
||||
GLUT_KEY_UP = 0x26,
|
||||
GLUT_KEY_DOWN = 0x28
|
||||
};
|
||||
|
||||
|
||||
/* glutSetCursor */
|
||||
#define GLUT_CURSOR_INHERIT 32512 /* IDC_* */
|
||||
#define GLUT_CURSOR_WAIT 32514
|
||||
#define GLUT_CURSOR_DESTROY 32648
|
||||
#define GLUT_CURSOR_NONE 0
|
||||
|
||||
/* glutGet */
|
||||
enum
|
||||
{
|
||||
GLUT_ELAPSED_TIME,
|
||||
GLUT_SCREEN_WIDTH,
|
||||
GLUT_SCREEN_HEIGHT,
|
||||
|
||||
GLUT_GAME_MODE_WIDTH,
|
||||
GLUT_GAME_MODE_HEIGHT,
|
||||
GLUT_GAME_MODE_PIXEL_DEPTH,
|
||||
GLUT_GAME_MODE_REFRESH_RATE
|
||||
};
|
||||
|
||||
|
||||
|
||||
extern void glutIdleFunc(void(*)());
|
||||
extern void glutDisplayFunc(void(*)());
|
||||
extern void glutKeyboardFunc(void(*)(int, int, int));
|
||||
extern void glutSpecialFunc(void(*)(int, int, int));
|
||||
extern void glutMouseFunc(void(*)(int, int, int, int));
|
||||
|
||||
|
||||
#define glutInitDisplayMode(a) /* pixel format is hardwired */
|
||||
|
||||
extern int glutGameModeString(const char* str);
|
||||
|
||||
|
||||
|
||||
extern void glutInit(int* argc, char* argv[]);
|
||||
extern int glutGet(int arg);
|
||||
extern int glutEnterGameMode();
|
||||
extern void glutMainLoop();
|
||||
|
||||
extern void glutPostRedisplay();
|
||||
|
||||
extern void glutSetCursor(int);
|
||||
|
||||
|
||||
|
||||
#define glutSwapBuffers SDL_GL_SwapBuffers
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #ifndef __WSDL_H__
|
108
source/terrain/Camera.cpp
Executable file
108
source/terrain/Camera.cpp
Executable file
@ -0,0 +1,108 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Camera.Cpp
|
||||
// Last Update: 24/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: CCamera holds a view and a projection matrix.
|
||||
// It also has a frustum which can be used to
|
||||
// cull objects for rendering.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#include "Camera.H"
|
||||
|
||||
extern int xres, yres;
|
||||
|
||||
CCamera::CCamera ()
|
||||
{
|
||||
m_ViewPort.m_Width = 1280;
|
||||
m_ViewPort.m_Height = 1024;
|
||||
m_ViewPort.m_X = 0;
|
||||
m_ViewPort.m_Y = 0;
|
||||
}
|
||||
|
||||
CCamera::~CCamera ()
|
||||
{
|
||||
}
|
||||
|
||||
void CCamera::SetProjection (float nearp, float farp, float fov)
|
||||
{
|
||||
float h, w, Q;
|
||||
|
||||
m_NearPlane = nearp;
|
||||
m_FarPlane = farp;
|
||||
m_FOV = fov;
|
||||
|
||||
float Aspect = (float)m_ViewPort.m_Width/(float)m_ViewPort.m_Height;
|
||||
|
||||
w = 1/tanf (fov*0.5f*Aspect);
|
||||
h = 1/tanf (fov*0.5f);
|
||||
Q = m_FarPlane / (m_FarPlane - m_NearPlane);
|
||||
|
||||
m_ProjMat.SetZero ();
|
||||
m_ProjMat._11 = w;
|
||||
m_ProjMat._22 = h;
|
||||
m_ProjMat._33 = Q;
|
||||
m_ProjMat._34 = -Q*m_NearPlane;
|
||||
m_ProjMat._43 = 1.0f;
|
||||
}
|
||||
|
||||
//Updates the frustum planes. Should be called
|
||||
//everytime the view or projection matrices are
|
||||
//altered.
|
||||
void CCamera::UpdateFrustum ()
|
||||
{
|
||||
CMatrix3D MatFinal;
|
||||
CMatrix3D MatView;
|
||||
|
||||
MatView = m_Orientation.GetTranspose ();
|
||||
|
||||
MatFinal = m_ProjMat * MatView;
|
||||
|
||||
//get the RIGHT plane
|
||||
m_ViewFrustum.SetNumPlanes (6);
|
||||
|
||||
m_ViewFrustum.m_aPlanes[0].m_Norm.X = MatFinal._41-MatFinal._11;
|
||||
m_ViewFrustum.m_aPlanes[0].m_Norm.Y = MatFinal._42-MatFinal._12;
|
||||
m_ViewFrustum.m_aPlanes[0].m_Norm.Z = MatFinal._43-MatFinal._13;
|
||||
m_ViewFrustum.m_aPlanes[0].m_Dist = MatFinal._44-MatFinal._14;
|
||||
|
||||
//get the LEFT plane
|
||||
m_ViewFrustum.m_aPlanes[1].m_Norm.X = MatFinal._41+MatFinal._11;
|
||||
m_ViewFrustum.m_aPlanes[1].m_Norm.Y = MatFinal._42+MatFinal._12;
|
||||
m_ViewFrustum.m_aPlanes[1].m_Norm.Z = MatFinal._43+MatFinal._13;
|
||||
m_ViewFrustum.m_aPlanes[1].m_Dist = MatFinal._44+MatFinal._14;
|
||||
|
||||
//get the BOTTOM plane
|
||||
m_ViewFrustum.m_aPlanes[2].m_Norm.X = MatFinal._41+MatFinal._21;
|
||||
m_ViewFrustum.m_aPlanes[2].m_Norm.Y = MatFinal._42+MatFinal._22;
|
||||
m_ViewFrustum.m_aPlanes[2].m_Norm.Z = MatFinal._43+MatFinal._23;
|
||||
m_ViewFrustum.m_aPlanes[2].m_Dist = MatFinal._44+MatFinal._24;
|
||||
|
||||
//get the TOP plane
|
||||
m_ViewFrustum.m_aPlanes[3].m_Norm.X = MatFinal._41-MatFinal._21;
|
||||
m_ViewFrustum.m_aPlanes[3].m_Norm.Y = MatFinal._42-MatFinal._22;
|
||||
m_ViewFrustum.m_aPlanes[3].m_Norm.Z = MatFinal._43-MatFinal._23;
|
||||
m_ViewFrustum.m_aPlanes[3].m_Dist = MatFinal._44-MatFinal._24;
|
||||
|
||||
//get the FAR plane
|
||||
m_ViewFrustum.m_aPlanes[4].m_Norm.X = MatFinal._41-MatFinal._31;
|
||||
m_ViewFrustum.m_aPlanes[4].m_Norm.Y = MatFinal._42-MatFinal._32;
|
||||
m_ViewFrustum.m_aPlanes[4].m_Norm.Z = MatFinal._43-MatFinal._33;
|
||||
m_ViewFrustum.m_aPlanes[4].m_Dist = MatFinal._44-MatFinal._34;
|
||||
|
||||
//get the NEAR plane
|
||||
m_ViewFrustum.m_aPlanes[5].m_Norm.X = MatFinal._41+MatFinal._31;
|
||||
m_ViewFrustum.m_aPlanes[5].m_Norm.Y = MatFinal._42+MatFinal._32;
|
||||
m_ViewFrustum.m_aPlanes[5].m_Norm.Z = MatFinal._43+MatFinal._33;
|
||||
m_ViewFrustum.m_aPlanes[5].m_Dist = MatFinal._44+MatFinal._34;
|
||||
}
|
||||
|
||||
void CCamera::SetViewPort (SViewPort *viewport)
|
||||
{
|
||||
m_ViewPort.m_X = viewport->m_X;
|
||||
m_ViewPort.m_Y = viewport->m_Y;
|
||||
m_ViewPort.m_Width = viewport->m_Width;
|
||||
m_ViewPort.m_Height = viewport->m_Height;
|
||||
}
|
72
source/terrain/Camera.h
Executable file
72
source/terrain/Camera.h
Executable file
@ -0,0 +1,72 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Camera.H
|
||||
// Last Update: 24/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: CCamera holds a view and a projection matrix.
|
||||
// It also has a frustum which can be used to
|
||||
// cull objects for rendering.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef CAMERA_H
|
||||
#define CAMERA_H
|
||||
|
||||
#include "Frustum.H"
|
||||
#include "Matrix3D.H"
|
||||
|
||||
//view port
|
||||
struct SViewPort
|
||||
{
|
||||
unsigned int m_X;
|
||||
unsigned int m_Y;
|
||||
unsigned int m_Width;
|
||||
unsigned int m_Height;
|
||||
};
|
||||
|
||||
|
||||
class CCamera
|
||||
{
|
||||
public:
|
||||
CCamera ();
|
||||
~CCamera ();
|
||||
|
||||
//Methods for projection
|
||||
void SetProjection (CMatrix3D *proj) { m_ProjMat = *proj; }
|
||||
void SetProjection (float nearp, float farp, float fov);
|
||||
CMatrix3D GetProjection () { return m_ProjMat; }
|
||||
|
||||
//Updates the frustum planes. Should be called
|
||||
//everytime the view or projection matrices are
|
||||
//altered.
|
||||
void UpdateFrustum ();
|
||||
CFrustum GetFustum () { return m_ViewFrustum; }
|
||||
|
||||
void SetViewPort (SViewPort *viewport);
|
||||
SViewPort GetViewPort () { return m_ViewPort; }
|
||||
|
||||
//getters
|
||||
float GetNearPlane () { return m_NearPlane; }
|
||||
float GetFarPlane () { return m_FarPlane; }
|
||||
float GetFOV () { return m_FOV; }
|
||||
|
||||
public:
|
||||
//This is the orientation matrix. The inverse of this
|
||||
//is the view matrix
|
||||
CMatrix3D m_Orientation;
|
||||
|
||||
private:
|
||||
//keep the projection matrix private
|
||||
//so we can't fiddle with it.
|
||||
CMatrix3D m_ProjMat;
|
||||
|
||||
float m_NearPlane;
|
||||
float m_FarPlane;
|
||||
float m_FOV;
|
||||
SViewPort m_ViewPort;
|
||||
|
||||
CFrustum m_ViewFrustum;
|
||||
};
|
||||
|
||||
#endif
|
144
source/terrain/Frustum.cpp
Executable file
144
source/terrain/Frustum.cpp
Executable file
@ -0,0 +1,144 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Frustum.Cpp
|
||||
// Last Update: 24/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: CFrustum is a collection of planes which define
|
||||
// a viewing space. Usually associated with the
|
||||
// camera, there are 6 planes which define the
|
||||
// view pyramid. But we allow more planes per
|
||||
// frustum which maybe used for portal rendering,
|
||||
// where a portal may have 3 or more edges.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#include "Frustum.H"
|
||||
|
||||
CFrustum::CFrustum ()
|
||||
{
|
||||
m_NumPlanes = 0;
|
||||
}
|
||||
|
||||
CFrustum::~CFrustum ()
|
||||
{
|
||||
}
|
||||
|
||||
void CFrustum::SetNumPlanes (int num)
|
||||
{
|
||||
m_NumPlanes = num;
|
||||
|
||||
//clip it
|
||||
if (m_NumPlanes >= MAX_NUM_FRUSTUM_PLANES)
|
||||
m_NumPlanes = MAX_NUM_FRUSTUM_PLANES-1;
|
||||
else if (m_NumPlanes < 0)
|
||||
m_NumPlanes = 0;
|
||||
}
|
||||
|
||||
bool CFrustum::IsPointVisible (CVector3D &point)
|
||||
{
|
||||
PLANESIDE Side;
|
||||
|
||||
for (int i=0; i<m_NumPlanes; i++)
|
||||
{
|
||||
Side = m_aPlanes[i].ClassifyPoint (point);
|
||||
|
||||
if (Side == PS_BACK)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CFrustum::IsSphereVisible (CVector3D ¢er, float radius)
|
||||
{
|
||||
for (int i=0; i<m_NumPlanes; i++)
|
||||
{
|
||||
float Dist = m_aPlanes[i].DistanceToPlane (center);
|
||||
|
||||
//is it behind the plane
|
||||
if (Dist < 0)
|
||||
{
|
||||
//if non of it falls in front its outside the
|
||||
//frustum
|
||||
if (-Dist > radius)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CFrustum::IsBoxVisible (CVector3D &position, SBoundingBox &bounds)
|
||||
{
|
||||
//basically for every plane we calculate the furthust point
|
||||
//in the box to that plane. If that point is beyond the plane
|
||||
//then the box is not visible
|
||||
CVector3D FarPoint;
|
||||
PLANESIDE Side;
|
||||
CVector3D Min = position+bounds.m_BoxMin;
|
||||
CVector3D Max = position+bounds.m_BoxMax;
|
||||
|
||||
for (int i=0; i<m_NumPlanes; i++)
|
||||
{
|
||||
if (m_aPlanes[i].m_Norm.X > 0.0f)
|
||||
{
|
||||
if (m_aPlanes[i].m_Norm.Y > 0.0f)
|
||||
{
|
||||
if (m_aPlanes[i].m_Norm.Z > 0.0f)
|
||||
{
|
||||
FarPoint.X = Max.X; FarPoint.Y = Max.Y; FarPoint.Z = Max.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
FarPoint.X = Max.X; FarPoint.Y = Max.Y; FarPoint.Z = Min.Z;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_aPlanes[i].m_Norm.Z > 0.0f)
|
||||
{
|
||||
FarPoint.X = Max.X; FarPoint.Y = Min.Y; FarPoint.Z = Max.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
FarPoint.X = Max.X; FarPoint.Y = Min.Y; FarPoint.Z = Min.Z;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_aPlanes[i].m_Norm.Y > 0.0f)
|
||||
{
|
||||
if (m_aPlanes[i].m_Norm.Z > 0.0f)
|
||||
{
|
||||
FarPoint.X = Min.X; FarPoint.Y = Max.Y; FarPoint.Z = Max.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
FarPoint.X = Min.X; FarPoint.Y = Max.Y; FarPoint.Z = Min.Z;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_aPlanes[i].m_Norm.Z > 0.0f)
|
||||
{
|
||||
FarPoint.X = Min.X; FarPoint.Y = Min.Y; FarPoint.Z = Max.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
FarPoint.X = Min.X; FarPoint.Y = Min.Y; FarPoint.Z = Min.Z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Side = m_aPlanes[i].ClassifyPoint (FarPoint);
|
||||
|
||||
if (Side == PS_BACK)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
56
source/terrain/Frustum.h
Executable file
56
source/terrain/Frustum.h
Executable file
@ -0,0 +1,56 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Frustum.H
|
||||
// Last Update: 24/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: CFrustum is a collection of planes which define
|
||||
// a viewing space. Usually associated with the
|
||||
// camera, there are 6 planes which define the
|
||||
// view pyramid. But we allow more planes per
|
||||
// frustum which maybe used for portal rendering,
|
||||
// where a portal may have 3 or more edges.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef FRUSTUM_H
|
||||
#define FRUSTUM_H
|
||||
|
||||
#include "Plane.H"
|
||||
|
||||
//10 planes should be enough
|
||||
#define MAX_NUM_FRUSTUM_PLANES (10)
|
||||
|
||||
|
||||
struct SBoundingBox
|
||||
{
|
||||
CVector3D m_BoxMin;
|
||||
CVector3D m_BoxMax;
|
||||
};
|
||||
|
||||
class CFrustum
|
||||
{
|
||||
public:
|
||||
CFrustum ();
|
||||
~CFrustum ();
|
||||
|
||||
//Set the number of planes to use for
|
||||
//calculations. This is clipped to
|
||||
//[0,MAX_NUM_FRUSTUM_PLANES]
|
||||
void SetNumPlanes (int num);
|
||||
|
||||
//The following methods return true if the shape is
|
||||
//partially or completely in front of the frustum planes
|
||||
bool IsPointVisible (CVector3D &point);
|
||||
bool IsSphereVisible (CVector3D ¢er, float radius);
|
||||
bool IsBoxVisible (CVector3D &position, SBoundingBox &bounds);
|
||||
|
||||
public:
|
||||
//make the planes public for ease of use
|
||||
CPlane m_aPlanes[MAX_NUM_FRUSTUM_PLANES];
|
||||
|
||||
private:
|
||||
int m_NumPlanes;
|
||||
};
|
||||
|
||||
#endif
|
26
source/terrain/MathUtil.h
Executable file
26
source/terrain/MathUtil.h
Executable file
@ -0,0 +1,26 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: MathUtil.H
|
||||
// Last Update: 28/1/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: This file contains some maths related
|
||||
// utility macros and fucntions.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef MATHUTIL_H
|
||||
#define MATHUTIL_H
|
||||
|
||||
#define PI 3.14159265358979323846f
|
||||
|
||||
#define DEGTORAD(a) (((a) * PI) / 180.0f)
|
||||
#define SQR(x) ((x) * (x))
|
||||
#define MAX(a,b) ((a < b) ? (b) : (a))
|
||||
#define MIN(a,b) ((a < b) ? (a) : (b))
|
||||
#define MAX3(a,b,c) ( MAX (MAX(a,b), c) )
|
||||
#define ABS(a) ((a > 0) ? (a) : (-a))
|
||||
|
||||
//extern unsigned int F2DW (float f);
|
||||
|
||||
#endif
|
384
source/terrain/Matrix3D.cpp
Executable file
384
source/terrain/Matrix3D.cpp
Executable file
@ -0,0 +1,384 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Matrix3D.Cpp
|
||||
// Last Update: 31/1/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: A Matrix class used for holding and
|
||||
// manipulating transformation info.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#include "Matrix3D.H"
|
||||
|
||||
CMatrix3D::CMatrix3D ()
|
||||
{
|
||||
SetIdentity ();
|
||||
}
|
||||
|
||||
//Matrix multiplication
|
||||
CMatrix3D CMatrix3D::operator * (CMatrix3D &matrix)
|
||||
{
|
||||
CMatrix3D Temp;
|
||||
|
||||
Temp._11 = _11*matrix._11 +
|
||||
_12*matrix._21 +
|
||||
_13*matrix._31 +
|
||||
_14*matrix._41;
|
||||
|
||||
Temp._12 = _11*matrix._12 +
|
||||
_12*matrix._22 +
|
||||
_13*matrix._32 +
|
||||
_14*matrix._42;
|
||||
|
||||
Temp._13 = _11*matrix._13 +
|
||||
_12*matrix._23 +
|
||||
_13*matrix._33 +
|
||||
_14*matrix._43;
|
||||
|
||||
Temp._14 = _11*matrix._14 +
|
||||
_12*matrix._24 +
|
||||
_13*matrix._34 +
|
||||
_14*matrix._44;
|
||||
|
||||
Temp._21 = _21*matrix._11 +
|
||||
_22*matrix._21 +
|
||||
_23*matrix._31 +
|
||||
_24*matrix._41;
|
||||
|
||||
Temp._22 = _21*matrix._12 +
|
||||
_22*matrix._22 +
|
||||
_23*matrix._32 +
|
||||
_24*matrix._42;
|
||||
|
||||
Temp._23 = _21*matrix._13 +
|
||||
_22*matrix._23 +
|
||||
_23*matrix._33 +
|
||||
_24*matrix._43;
|
||||
|
||||
Temp._24 = _21*matrix._14 +
|
||||
_22*matrix._24 +
|
||||
_23*matrix._34 +
|
||||
_24*matrix._44;
|
||||
|
||||
Temp._31 = _31*matrix._11 +
|
||||
_32*matrix._21 +
|
||||
_33*matrix._31 +
|
||||
_34*matrix._41;
|
||||
|
||||
Temp._32 = _31*matrix._12 +
|
||||
_32*matrix._22 +
|
||||
_33*matrix._32 +
|
||||
_34*matrix._42;
|
||||
|
||||
Temp._33 = _31*matrix._13 +
|
||||
_32*matrix._23 +
|
||||
_33*matrix._33 +
|
||||
_34*matrix._43;
|
||||
|
||||
Temp._34 = _31*matrix._14 +
|
||||
_32*matrix._24 +
|
||||
_33*matrix._34 +
|
||||
_34*matrix._44;
|
||||
|
||||
Temp._41 = _41*matrix._11 +
|
||||
_42*matrix._21 +
|
||||
_43*matrix._31 +
|
||||
_44*matrix._41;
|
||||
|
||||
Temp._42 = _41*matrix._12 +
|
||||
_42*matrix._22 +
|
||||
_43*matrix._32 +
|
||||
_44*matrix._42;
|
||||
|
||||
Temp._43 = _41*matrix._13 +
|
||||
_42*matrix._23 +
|
||||
_43*matrix._33 +
|
||||
_44*matrix._43;
|
||||
|
||||
Temp._44 = _41*matrix._14 +
|
||||
_42*matrix._24 +
|
||||
_43*matrix._34 +
|
||||
_44*matrix._44;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//Matrix multiplication/assignment
|
||||
CMatrix3D &CMatrix3D::operator *= (CMatrix3D &matrix)
|
||||
{
|
||||
CMatrix3D &Temp = (*this) * matrix;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//Sets the identity matrix
|
||||
void CMatrix3D::SetIdentity ()
|
||||
{
|
||||
_11=1.0f; _12=0.0f; _13=0.0f; _14=0.0f;
|
||||
_21=0.0f; _22=1.0f; _23=0.0f; _24=0.0f;
|
||||
_31=0.0f; _32=0.0f; _33=1.0f; _34=0.0f;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
|
||||
}
|
||||
|
||||
//Sets the zero matrix
|
||||
void CMatrix3D::SetZero ()
|
||||
{
|
||||
_11=0.0f; _12=0.0f; _13=0.0f; _14=0.0f;
|
||||
_21=0.0f; _22=0.0f; _23=0.0f; _24=0.0f;
|
||||
_31=0.0f; _32=0.0f; _33=0.0f; _34=0.0f;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=0.0f;
|
||||
}
|
||||
|
||||
//The following clear the matrix and set the
|
||||
//rotation of each of the 3 axes
|
||||
|
||||
void CMatrix3D::SetXRotation (float angle)
|
||||
{
|
||||
float Cos = cosf (angle);
|
||||
float Sin = sinf (angle);
|
||||
|
||||
_11=1.0f; _12=0.0f; _13=0.0f; _14=0.0f;
|
||||
_21=0.0f; _22=Cos; _23=-Sin; _24=0.0f;
|
||||
_31=0.0f; _32=Sin; _33=Cos; _34=0.0f;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
|
||||
}
|
||||
|
||||
void CMatrix3D::SetYRotation (float angle)
|
||||
{
|
||||
float Cos = cosf (angle);
|
||||
float Sin = sinf (angle);
|
||||
|
||||
_11=Cos; _12=0.0f; _13=Sin; _14=0.0f;
|
||||
_21=0.0f; _22=1.0f; _23=0.0f; _24=0.0f;
|
||||
_31=-Sin; _32=0.0f; _33=Cos; _34=0.0f;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
|
||||
}
|
||||
|
||||
void CMatrix3D::SetZRotation (float angle)
|
||||
{
|
||||
float Cos = cosf (angle);
|
||||
float Sin = sinf (angle);
|
||||
|
||||
_11=Cos; _12=-Sin; _13=0.0f; _14=0.0f;
|
||||
_21=Sin; _22=Cos; _23=0.0f; _24=0.0f;
|
||||
_31=0.0f; _32=0.0f; _33=1.0f; _34=0.0f;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
|
||||
}
|
||||
|
||||
//The following apply a rotation to the matrix
|
||||
//about each of the axes;
|
||||
|
||||
void CMatrix3D::RotateX (float angle)
|
||||
{
|
||||
CMatrix3D Temp;
|
||||
Temp.SetXRotation (angle);
|
||||
|
||||
(*this) = Temp * (*this);
|
||||
}
|
||||
|
||||
void CMatrix3D::RotateY (float angle)
|
||||
{
|
||||
CMatrix3D Temp;
|
||||
Temp.SetYRotation (angle);
|
||||
|
||||
(*this) = Temp * (*this);
|
||||
}
|
||||
|
||||
void CMatrix3D::RotateZ (float angle)
|
||||
{
|
||||
CMatrix3D Temp;
|
||||
Temp.SetZRotation (angle);
|
||||
|
||||
(*this) = Temp * (*this);
|
||||
}
|
||||
|
||||
//Sets the translation of the matrix
|
||||
void CMatrix3D::SetTranslation (float x, float y, float z)
|
||||
{
|
||||
_11=1.0f; _12=0.0f; _13=0.0f; _14=x;
|
||||
_21=0.0f; _22=1.0f; _23=0.0f; _24=y;
|
||||
_31=0.0f; _32=0.0f; _33=1.0f; _34=z;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
|
||||
}
|
||||
|
||||
void CMatrix3D::SetTranslation (CVector3D &vector)
|
||||
{
|
||||
SetTranslation (vector.X, vector.Y, vector.Z);
|
||||
}
|
||||
|
||||
//Applies a translation to the matrix
|
||||
void CMatrix3D::Translate (float x, float y, float z)
|
||||
{
|
||||
CMatrix3D Temp;
|
||||
Temp.SetTranslation (x, y, z);
|
||||
|
||||
(*this) = Temp * (*this);
|
||||
}
|
||||
|
||||
void CMatrix3D::Translate (CVector3D &vector)
|
||||
{
|
||||
Translate (vector.X, vector.Y, vector.Z);
|
||||
}
|
||||
|
||||
CVector3D CMatrix3D::GetTranslation ()
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = _14;
|
||||
Temp.Y = _24;
|
||||
Temp.Z = _34;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//Clears and sets the scaling of the matrix
|
||||
void CMatrix3D::SetScaling (float x_scale, float y_scale, float z_scale)
|
||||
{
|
||||
_11=x_scale; _12=0.0f; _13=0.0f; _14=0.0f;
|
||||
_21=0.0f; _22=y_scale; _23=0.0f; _24=0.0f;
|
||||
_31=0.0f; _32=0.0f; _33=z_scale; _34=0.0f;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
|
||||
}
|
||||
|
||||
//Scales the matrix
|
||||
void CMatrix3D::Scale (float x_scale, float y_scale, float z_scale)
|
||||
{
|
||||
CMatrix3D Temp;
|
||||
Temp.SetScaling (x_scale, y_scale, z_scale);
|
||||
|
||||
(*this) = Temp * (*this);
|
||||
}
|
||||
|
||||
//Returns the transpose of the matrix. For orthonormal
|
||||
//matrices, this is the same is the inverse matrix
|
||||
CMatrix3D CMatrix3D::GetTranspose ()
|
||||
{
|
||||
CMatrix3D Temp;
|
||||
|
||||
Temp._11 = _11;
|
||||
Temp._21 = _12;
|
||||
Temp._31 = _13;
|
||||
Temp._41 = 0.0f;
|
||||
|
||||
Temp._12 = _21;
|
||||
Temp._22 = _22;
|
||||
Temp._32 = _23;
|
||||
Temp._42 = 0.0f;
|
||||
|
||||
Temp._13 = _31;
|
||||
Temp._23 = _32;
|
||||
Temp._33 = _33;
|
||||
Temp._43 = 0.0f;
|
||||
|
||||
Temp._14 = 0.0f;
|
||||
Temp._24 = 0.0f;
|
||||
Temp._34 = 0.0f;
|
||||
Temp._44 = 1.0f;
|
||||
|
||||
CMatrix3D Trans;
|
||||
Trans.SetTranslation (-_14, -_24, -_34);
|
||||
|
||||
Temp = Temp * Trans;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//Get a vector which points to the left of the matrix
|
||||
CVector3D CMatrix3D::GetLeft ()
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = -_11;
|
||||
Temp.Y = -_21;
|
||||
Temp.Z = -_31;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//Get a vector which points up from the matrix
|
||||
CVector3D CMatrix3D::GetUp ()
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = _12;
|
||||
Temp.Y = _22;
|
||||
Temp.Z = _32;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//Get a vector which points to front of the matrix
|
||||
CVector3D CMatrix3D::GetIn ()
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = _13;
|
||||
Temp.Y = _23;
|
||||
Temp.Z = _33;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//Set the matrix from two vectors (Up and In)
|
||||
void CMatrix3D::SetFromUpIn (CVector3D &up, CVector3D &in, float scale)
|
||||
{
|
||||
CVector3D u = up;
|
||||
CVector3D i = in;
|
||||
|
||||
CVector3D r;
|
||||
|
||||
r = up.Cross (in);
|
||||
|
||||
u.Normalize (); u *= scale;
|
||||
i.Normalize (); i *= scale;
|
||||
r.Normalize (); r *= scale;
|
||||
|
||||
_11=r.X; _12=u.X; _13=i.X; _14=0.0f;
|
||||
_21=r.Y; _22=u.Y; _23=i.Y; _24=0.0f;
|
||||
_31=r.Z; _32=u.Z; _33=i.Z; _34=0.0f;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
|
||||
}
|
||||
|
||||
//Transform a vector by this matrix
|
||||
CVector3D CMatrix3D::Transform (CVector3D &vector)
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = _11*vector.X +
|
||||
_12*vector.Y +
|
||||
_13*vector.Z +
|
||||
_14;
|
||||
|
||||
Temp.Y = _21*vector.X +
|
||||
_22*vector.Y +
|
||||
_23*vector.Z +
|
||||
_24;
|
||||
|
||||
Temp.Z = _31*vector.X +
|
||||
_32*vector.Y +
|
||||
_33*vector.Z +
|
||||
_34;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//Only rotate (not translate) a vector by this matrix
|
||||
CVector3D CMatrix3D::Rotate (CVector3D &vector)
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = _11*vector.X +
|
||||
_12*vector.Y +
|
||||
_13*vector.Z;
|
||||
|
||||
Temp.Y = _21*vector.X +
|
||||
_22*vector.Y +
|
||||
_23*vector.Z;
|
||||
|
||||
Temp.Z = _31*vector.X +
|
||||
_32*vector.Y +
|
||||
_33*vector.Z;
|
||||
|
||||
return Temp;
|
||||
}
|
88
source/terrain/Matrix3D.h
Executable file
88
source/terrain/Matrix3D.h
Executable file
@ -0,0 +1,88 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Matrix3D.H
|
||||
// Last Update: 31/1/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: A Matrix class used for holding and
|
||||
// manipulating transformation info.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef MATRIX3D_H
|
||||
#define MATRIX3D_H
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "Vector3D.H"
|
||||
|
||||
class CMatrix3D
|
||||
{
|
||||
public:
|
||||
float _11, _12, _13, _14;
|
||||
float _21, _22, _23, _24;
|
||||
float _31, _32, _33, _34;
|
||||
float _41, _42, _43, _44;
|
||||
|
||||
public:
|
||||
CMatrix3D ();
|
||||
|
||||
//Matrix multiplication
|
||||
CMatrix3D operator * (CMatrix3D &matrix);
|
||||
//Matrix multiplication/assignment
|
||||
CMatrix3D &operator *= (CMatrix3D &matrix);
|
||||
|
||||
//Sets the identity matrix
|
||||
void SetIdentity ();
|
||||
//Sets the zero matrix
|
||||
void SetZero ();
|
||||
|
||||
//The following clear the matrix and set the
|
||||
//rotation of each of the 3 axes
|
||||
void SetXRotation (float angle);
|
||||
void SetYRotation (float angle);
|
||||
void SetZRotation (float angle);
|
||||
|
||||
//The following apply a rotation to the matrix
|
||||
//about each of the axes;
|
||||
void RotateX (float angle);
|
||||
void RotateY (float angle);
|
||||
void RotateZ (float angle);
|
||||
|
||||
//Sets the translation of the matrix
|
||||
void SetTranslation (float x, float y, float z);
|
||||
void SetTranslation (CVector3D &vector);
|
||||
|
||||
//Applies a translation to the matrix
|
||||
void Translate (float x, float y, float z);
|
||||
void Translate (CVector3D &vector);
|
||||
|
||||
CVector3D GetTranslation ();
|
||||
|
||||
//Clears and sets the scaling of the matrix
|
||||
void SetScaling (float x_scale, float y_scale, float z_scale);
|
||||
//Scales the matrix
|
||||
void Scale (float x_scale, float y_scale, float z_scale);
|
||||
|
||||
//Returns the transpose of the matrix. For orthonormal
|
||||
//matrices, this is the same is the inverse matrix
|
||||
CMatrix3D GetTranspose ();
|
||||
|
||||
//Get a vector which points to the left of the matrix
|
||||
CVector3D GetLeft ();
|
||||
//Get a vector which points up from the matrix
|
||||
CVector3D GetUp ();
|
||||
//Get a vector which points to front of the matrix
|
||||
CVector3D GetIn ();
|
||||
|
||||
//Set the matrix from two vectors (Up and In)
|
||||
void SetFromUpIn (CVector3D &up, CVector3D &in, float scale);
|
||||
|
||||
public: //Vector manipulation methods
|
||||
//Transform a vector by this matrix
|
||||
CVector3D Transform (CVector3D &vector);
|
||||
//Only rotate (not translate) a vector by this matrix
|
||||
CVector3D Rotate (CVector3D &vector);
|
||||
};
|
||||
|
||||
#endif
|
22
source/terrain/MiniPatch.cpp
Executable file
22
source/terrain/MiniPatch.cpp
Executable file
@ -0,0 +1,22 @@
|
||||
#include "MiniPatch.H"
|
||||
|
||||
CMiniPatch::CMiniPatch()
|
||||
{
|
||||
Tex1 = Tex2 = 0;
|
||||
m_AlphaMap = 0;
|
||||
m_pRightNeighbor = NULL;
|
||||
m_pParrent = NULL;
|
||||
m_Rotation = 0;
|
||||
m_RenderStage = 0;
|
||||
m_LastRenderedFrame = 0;
|
||||
}
|
||||
|
||||
CMiniPatch::~CMiniPatch()
|
||||
{
|
||||
}
|
||||
|
||||
void CMiniPatch::Initialize (STerrainVertex *first_vertex)
|
||||
{
|
||||
m_pVertices = first_vertex;
|
||||
|
||||
}
|
35
source/terrain/MiniPatch.h
Executable file
35
source/terrain/MiniPatch.h
Executable file
@ -0,0 +1,35 @@
|
||||
#ifndef MINIPATCH_H
|
||||
#define MINIPATCH_H
|
||||
|
||||
#include "Vector3D.H"
|
||||
#include "res.h"
|
||||
|
||||
struct STerrainVertex
|
||||
{
|
||||
CVector3D m_Position;
|
||||
float m_Color[2][3];
|
||||
};
|
||||
|
||||
|
||||
class CMiniPatch
|
||||
{
|
||||
public:
|
||||
CMiniPatch();
|
||||
~CMiniPatch();
|
||||
|
||||
void Initialize (STerrainVertex *first_vertex);
|
||||
|
||||
Handle Tex1, Tex2;
|
||||
Handle m_AlphaMap;
|
||||
CMiniPatch *m_pRightNeighbor;
|
||||
CPatch *m_pParrent;
|
||||
unsigned char m_RenderStage;
|
||||
unsigned int m_LastRenderedFrame;
|
||||
|
||||
unsigned char m_Rotation;
|
||||
|
||||
STerrainVertex *m_pVertices;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
61
source/terrain/Patch.cpp
Executable file
61
source/terrain/Patch.cpp
Executable file
@ -0,0 +1,61 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Patch.Cpp
|
||||
// Last Update: 23/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: CPatch is a smaller portion of the terrain.
|
||||
// It handles the ROAM implementation and its
|
||||
// own rendering.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#include "Patch.H"
|
||||
|
||||
|
||||
CPatch::CPatch ()
|
||||
{
|
||||
m_pVertices = NULL;
|
||||
}
|
||||
|
||||
CPatch::~CPatch ()
|
||||
{
|
||||
}
|
||||
|
||||
//Initialize the patch
|
||||
void CPatch::Initialize (STerrainVertex *first_vertex)
|
||||
{
|
||||
m_pVertices = first_vertex;
|
||||
|
||||
m_Bounds.m_BoxMin.X = m_pVertices[0].m_Position.X;
|
||||
m_Bounds.m_BoxMin.Z = m_pVertices[0].m_Position.Z;
|
||||
|
||||
m_Bounds.m_BoxMax.X = m_Bounds.m_BoxMin.X + PATCH_SIZE*CELL_SIZE;
|
||||
m_Bounds.m_BoxMax.Z = m_Bounds.m_BoxMin.Z + PATCH_SIZE*CELL_SIZE;
|
||||
|
||||
m_Bounds.m_BoxMin.Y = m_Bounds.m_BoxMin.Y = m_pVertices[0].m_Position.Y;
|
||||
|
||||
for (int j=0; j<PATCH_SIZE+1; j++)
|
||||
{
|
||||
for (int i=0; i<PATCH_SIZE+1; i++)
|
||||
{
|
||||
int pos = j*MAP_SIZE + i;
|
||||
|
||||
if (m_pVertices[pos].m_Position.Y < m_Bounds.m_BoxMin.Y)
|
||||
m_Bounds.m_BoxMin.Y = m_pVertices[pos].m_Position.Y;
|
||||
|
||||
if (m_pVertices[pos].m_Position.Y > m_Bounds.m_BoxMax.Y)
|
||||
m_Bounds.m_BoxMax.Y = m_pVertices[pos].m_Position.Y;
|
||||
}
|
||||
}
|
||||
|
||||
for (j=0; j<16; j++)
|
||||
{
|
||||
for (int i=0; i<16; i++)
|
||||
{
|
||||
int pos = (j*MAP_SIZE) + (i);
|
||||
m_MiniPatches[j][i].Initialize ( &m_pVertices[pos] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
39
source/terrain/Patch.h
Executable file
39
source/terrain/Patch.h
Executable file
@ -0,0 +1,39 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Patch.H
|
||||
// Last Update: 23/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: CPatch is a smaller portion of the terrain.
|
||||
// It handles its own rendering
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef PATCH_H
|
||||
#define PATCH_H
|
||||
|
||||
#include "Matrix3D.H"
|
||||
#include "Camera.H"
|
||||
#include "TerrGlobals.H"
|
||||
#include "MiniPatch.H"
|
||||
|
||||
class CPatch
|
||||
{
|
||||
public:
|
||||
CPatch ();
|
||||
~CPatch ();
|
||||
|
||||
//initialize the patch
|
||||
void Initialize (STerrainVertex *first_vertex);
|
||||
|
||||
// protected:
|
||||
CMiniPatch m_MiniPatches[16][16];
|
||||
|
||||
SBoundingBox m_Bounds;
|
||||
unsigned int m_LastVisFrame;
|
||||
|
||||
STerrainVertex *m_pVertices;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
138
source/terrain/Plane.cpp
Executable file
138
source/terrain/Plane.cpp
Executable file
@ -0,0 +1,138 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Plane.Cpp
|
||||
// Last Update: 17/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: A Plane in R3 and several utility methods.
|
||||
// Note that the format used for the plane
|
||||
// equation is Ax + By + Cz + D = 0, where
|
||||
// <A,B,C> is the normal vector.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#include "Plane.H"
|
||||
|
||||
CPlane::CPlane ()
|
||||
{
|
||||
m_Norm.Clear ();
|
||||
m_Dist = 0.0f;
|
||||
}
|
||||
|
||||
//sets the plane equation from 3 points on that plane
|
||||
void CPlane::Set (CVector3D &p1, CVector3D &p2, CVector3D &p3)
|
||||
{
|
||||
CVector3D D1, D2;
|
||||
CVector3D Norm;
|
||||
|
||||
//calculate two vectors on the surface of the plane
|
||||
D1 = p2-p1;
|
||||
D2 = p3-p1;
|
||||
|
||||
//cross multiply gives normal
|
||||
Norm = D2.Cross(D1);
|
||||
|
||||
Set (Norm, p1);
|
||||
}
|
||||
|
||||
//sets the plane equation from a normal and a point on
|
||||
//that plane
|
||||
void CPlane::Set (CVector3D &norm, CVector3D &point)
|
||||
{
|
||||
m_Norm = norm;
|
||||
|
||||
m_Dist = - (norm.X * point.X +
|
||||
norm.Y * point.Y +
|
||||
norm.Z * point.Z);
|
||||
|
||||
// Normalize ();
|
||||
}
|
||||
|
||||
//normalizes the plane equation
|
||||
void CPlane::Normalize ()
|
||||
{
|
||||
float Scale;
|
||||
|
||||
Scale = 1.0f/m_Norm.GetLength ();
|
||||
|
||||
m_Norm.X *= Scale;
|
||||
m_Norm.Y *= Scale;
|
||||
m_Norm.Z *= Scale;
|
||||
m_Dist *= Scale;
|
||||
}
|
||||
|
||||
//returns the side of the plane on which this point
|
||||
//lies.
|
||||
PLANESIDE CPlane::ClassifyPoint (CVector3D &point)
|
||||
{
|
||||
float Dist;
|
||||
|
||||
Dist = m_Norm.X * point.X +
|
||||
m_Norm.Y * point.Y +
|
||||
m_Norm.Z * point.Z +
|
||||
m_Dist;
|
||||
|
||||
if (Dist > 0.0f)
|
||||
return PS_FRONT;
|
||||
else if (Dist < 0.0f)
|
||||
return PS_BACK;
|
||||
|
||||
return PS_ON;
|
||||
}
|
||||
|
||||
//solves the plane equation for a particular point
|
||||
float CPlane::DistanceToPlane (CVector3D &point)
|
||||
{
|
||||
float Dist;
|
||||
|
||||
Dist = m_Norm.X * point.X +
|
||||
m_Norm.Y * point.Y +
|
||||
m_Norm.Z * point.Z +
|
||||
m_Dist;
|
||||
|
||||
return Dist;
|
||||
}
|
||||
|
||||
//calculates the intersection point of a line with this
|
||||
//plane. Returns false if there is no intersection
|
||||
bool CPlane::FindLineSegIntersection (CVector3D &start, CVector3D &end, CVector3D *intsect)
|
||||
{
|
||||
PLANESIDE StartS, EndS;
|
||||
CVector3D Dir;
|
||||
float Length;
|
||||
|
||||
//work out where each point is
|
||||
StartS = ClassifyPoint (start);
|
||||
EndS = ClassifyPoint (end);
|
||||
|
||||
//if they are not on opposite sides of the plane return false
|
||||
if (StartS == EndS)
|
||||
return false;
|
||||
|
||||
//work out a normalized vector in the direction start to end
|
||||
Dir = end - start;
|
||||
Dir.Normalize ();
|
||||
|
||||
//a bit of algebra to work out how much we need to scale
|
||||
//this direction vector to get to the plane
|
||||
Length = -m_Norm.Dot(start)/m_Norm.Dot(Dir);
|
||||
|
||||
//scale it by this amount
|
||||
Dir *= Length;
|
||||
|
||||
//workout actual position vector of impact
|
||||
*intsect = start + Dir;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPlane::FindRayIntersection (CVector3D &start, CVector3D &direction, CVector3D *intsect)
|
||||
{
|
||||
float dot = m_Norm.Dot (direction);
|
||||
if (dot == 0.0f)
|
||||
return false;
|
||||
|
||||
CVector3D a;
|
||||
*intsect = start - (direction * (DistanceToPlane (start)/dot));
|
||||
return true;
|
||||
}
|
58
source/terrain/Plane.h
Executable file
58
source/terrain/Plane.h
Executable file
@ -0,0 +1,58 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Plane.H
|
||||
// Last Update: 17/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: A Plane in R3 and several utility methods.
|
||||
// Note that the format used for the plane
|
||||
// equation is Ax + By + Cz + D = 0, where
|
||||
// <A,B,C> is the normal vector.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef PLANE_H
|
||||
#define PLANE_H
|
||||
|
||||
#include "Vector3D.H"
|
||||
|
||||
enum PLANESIDE
|
||||
{
|
||||
PS_FRONT,
|
||||
PS_BACK,
|
||||
PS_ON
|
||||
};
|
||||
|
||||
class CPlane
|
||||
{
|
||||
public:
|
||||
CPlane ();
|
||||
|
||||
//sets the plane equation from 3 points on that plane
|
||||
void Set (CVector3D &p1, CVector3D &p2, CVector3D &p3);
|
||||
|
||||
//sets the plane equation from a normal and a point on
|
||||
//that plane
|
||||
void Set (CVector3D &norm, CVector3D &point);
|
||||
|
||||
//normalizes the plane equation
|
||||
void Normalize ();
|
||||
|
||||
//returns the side of the plane on which this point
|
||||
//lies.
|
||||
PLANESIDE ClassifyPoint (CVector3D &point);
|
||||
|
||||
//solves the plane equation for a particular point
|
||||
float DistanceToPlane (CVector3D &point);
|
||||
|
||||
//calculates the intersection point of a line with this
|
||||
//plane. Returns false if there is no intersection
|
||||
bool FindLineSegIntersection (CVector3D &start, CVector3D &end, CVector3D *intsect);
|
||||
bool FindRayIntersection (CVector3D &start, CVector3D &direction, CVector3D *intsect);
|
||||
|
||||
public:
|
||||
CVector3D m_Norm; //normal vector of the plane
|
||||
float m_Dist; //Plane distance (ie D in the plane eq.)
|
||||
};
|
||||
|
||||
#endif
|
467
source/terrain/Renderer.cpp
Executable file
467
source/terrain/Renderer.cpp
Executable file
@ -0,0 +1,467 @@
|
||||
#include "Renderer.H"
|
||||
#include "Matrix3D.H"
|
||||
#include "Camera.H"
|
||||
|
||||
#include "types.h"
|
||||
#include "ogl.h"
|
||||
#include "tex.h"
|
||||
|
||||
#define RENDER_STAGE_BASE (1)
|
||||
#define RENDER_STAGE_TRANS (2)
|
||||
|
||||
bool g_WireFrame = false;
|
||||
unsigned int g_FrameCounter = 0;
|
||||
|
||||
CRenderer::CRenderer ()
|
||||
{
|
||||
m_Timer = 0;
|
||||
m_CurrentSeason = 0;
|
||||
}
|
||||
|
||||
CRenderer::~CRenderer ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool CRenderer::Initialize (HWND hwnd, int width, int height, int depth)
|
||||
{
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Depth = depth;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CRenderer::Shutdown ()
|
||||
{
|
||||
|
||||
}
|
||||
/*
|
||||
struct Tile
|
||||
{
|
||||
u32 pri_tex : 5;
|
||||
u32 sec_tex : 5;
|
||||
u32 alpha_map : 6;
|
||||
};
|
||||
|
||||
|
||||
void render_terrain()
|
||||
{
|
||||
CMatrix3D view = camera->m_Orientation.GetTranspose();
|
||||
CMatrix3D proj = camera->GetProjection();
|
||||
|
||||
float gl_view[16] = {view._11, view._21, view._31, view._41,
|
||||
view._12, view._22, view._32, view._42,
|
||||
view._13, view._23, view._33, view._43,
|
||||
view._14, view._24, view._34, view._44};
|
||||
|
||||
float gl_proj[16] = {proj._11, proj._21, proj._31, proj._41,
|
||||
proj._12, proj._22, proj._32, proj._42,
|
||||
proj._13, proj._23, proj._33, proj._43,
|
||||
proj._14, proj._24, proj._34, proj._44};
|
||||
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
glLoadMatrixf (gl_view);
|
||||
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glLoadMatrixf (gl_proj);
|
||||
|
||||
SViewPort vp = camera->GetViewPort();
|
||||
glViewport (vp.m_X, vp.m_Y, vp.m_Width, vp.m_Height);
|
||||
|
||||
if (g_WireFrame)
|
||||
glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
|
||||
else
|
||||
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
|
||||
for (int j=0; j<NUM_PATCHES_PER_SIDE; j++)
|
||||
{
|
||||
for (int i=0; i<NUM_PATCHES_PER_SIDE; i++)
|
||||
{
|
||||
if (camera->GetFustum().IsBoxVisible (CVector3D(0,0,0), terrain->m_Patches[j][i].m_Bounds))
|
||||
terrain->m_Patches[j][i].m_LastVisFrame = g_FrameCounter;
|
||||
}
|
||||
}
|
||||
|
||||
for (j=0; j<NUM_PATCHES_PER_SIDE; j++)
|
||||
{
|
||||
for (int i=0; i<NUM_PATCHES_PER_SIDE; i++)
|
||||
{
|
||||
if (terrain->m_Patches[j][i].m_LastVisFrame == g_FrameCounter)
|
||||
render_patch(&terrain->m_Patches[j][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
void CRenderer::RenderTerrain (CTerrain *terrain, CCamera *camera)
|
||||
{
|
||||
// m_Timer += 0.001f;
|
||||
|
||||
if (m_Timer > 1.0f)
|
||||
{
|
||||
m_Timer = 0;
|
||||
|
||||
if (m_CurrentSeason == 0)
|
||||
m_CurrentSeason = 1;
|
||||
else
|
||||
m_CurrentSeason = 0;
|
||||
}
|
||||
|
||||
CMatrix3D view = camera->m_Orientation.GetTranspose();
|
||||
CMatrix3D proj = camera->GetProjection();
|
||||
|
||||
float gl_view[16] = {view._11, view._21, view._31, view._41,
|
||||
view._12, view._22, view._32, view._42,
|
||||
view._13, view._23, view._33, view._43,
|
||||
view._14, view._24, view._34, view._44};
|
||||
|
||||
float gl_proj[16] = {proj._11, proj._21, proj._31, proj._41,
|
||||
proj._12, proj._22, proj._32, proj._42,
|
||||
proj._13, proj._23, proj._33, proj._43,
|
||||
proj._14, proj._24, proj._34, proj._44};
|
||||
|
||||
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
glLoadMatrixf (gl_view);
|
||||
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glLoadMatrixf (gl_proj);
|
||||
|
||||
SViewPort vp = camera->GetViewPort();
|
||||
glViewport (vp.m_X, vp.m_Y, vp.m_Width, vp.m_Height);
|
||||
|
||||
if (g_WireFrame)
|
||||
glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
|
||||
else
|
||||
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
|
||||
for (int j=0; j<NUM_PATCHES_PER_SIDE; j++)
|
||||
{
|
||||
for (int i=0; i<NUM_PATCHES_PER_SIDE; i++)
|
||||
{
|
||||
if (camera->GetFustum().IsBoxVisible (CVector3D(0,0,0), terrain->m_Patches[j][i].m_Bounds))
|
||||
terrain->m_Patches[j][i].m_LastVisFrame = g_FrameCounter;
|
||||
}
|
||||
}
|
||||
|
||||
for (j=0; j<NUM_PATCHES_PER_SIDE; j++)
|
||||
{
|
||||
for (int i=0; i<NUM_PATCHES_PER_SIDE; i++)
|
||||
{
|
||||
if (terrain->m_Patches[j][i].m_LastVisFrame == g_FrameCounter)
|
||||
RenderPatchBase (&terrain->m_Patches[j][i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (j=0; j<NUM_PATCHES_PER_SIDE; j++)
|
||||
{
|
||||
for (int i=0; i<NUM_PATCHES_PER_SIDE; i++)
|
||||
{
|
||||
if (terrain->m_Patches[j][i].m_LastVisFrame == g_FrameCounter)
|
||||
RenderPatchTrans (&terrain->m_Patches[j][i]);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CRenderer::RenderPatchBase (CPatch *patch)
|
||||
{
|
||||
CMiniPatch *MPatch, *MPCurrent;
|
||||
|
||||
float StartU, StartV;
|
||||
|
||||
|
||||
for (int j=0; j<16; j++)
|
||||
{
|
||||
for (int i=0; i<16; i++)
|
||||
{
|
||||
MPatch = &(patch->m_MiniPatches[j][i]);
|
||||
|
||||
if (MPatch->m_LastRenderedFrame == g_FrameCounter)
|
||||
continue;
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
tex_bind(MPatch->Tex1);
|
||||
|
||||
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
/////////////////////////////////////
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
||||
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
||||
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
|
||||
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
/////////////////////////////////////
|
||||
|
||||
StartU = 0.125f * (float)(i%8);
|
||||
StartV = 0.125f * (float)(j%8);
|
||||
|
||||
float tu[2], tv[2];
|
||||
tu[0] = tu[1] = StartU;
|
||||
tv[0] = StartV+0.125f;
|
||||
tv[1] = StartV;
|
||||
|
||||
MPCurrent = MPatch;
|
||||
glBegin (GL_TRIANGLE_STRIP);
|
||||
|
||||
int start = 0;
|
||||
|
||||
while (MPCurrent)
|
||||
{
|
||||
for (int x=start; x<2; x++)
|
||||
{
|
||||
int v1 = MAP_SIZE + x;
|
||||
int v2 = x;
|
||||
|
||||
float factor = m_Timer;
|
||||
if (m_CurrentSeason == 1)
|
||||
factor = 1.0f - factor;
|
||||
|
||||
float color1[3] = {MPCurrent->m_pVertices[v1].m_Color[0][0]*factor + MPCurrent->m_pVertices[v1].m_Color[1][0]*(1.0f-factor),
|
||||
MPCurrent->m_pVertices[v1].m_Color[0][1]*factor + MPCurrent->m_pVertices[v1].m_Color[1][1]*(1.0f-factor),
|
||||
MPCurrent->m_pVertices[v1].m_Color[0][2]*factor + MPCurrent->m_pVertices[v1].m_Color[1][2]*(1.0f-factor)};
|
||||
|
||||
float color2[3] = {MPCurrent->m_pVertices[v2].m_Color[0][0]*factor + MPCurrent->m_pVertices[v2].m_Color[1][0]*(1.0f-factor),
|
||||
MPCurrent->m_pVertices[v2].m_Color[0][1]*factor + MPCurrent->m_pVertices[v2].m_Color[1][1]*(1.0f-factor),
|
||||
MPCurrent->m_pVertices[v2].m_Color[0][2]*factor + MPCurrent->m_pVertices[v2].m_Color[1][2]*(1.0f-factor)};
|
||||
|
||||
glTexCoord2f (tu[0], tv[0]);
|
||||
|
||||
if (g_HillShading)
|
||||
glColor3f (color1[0],color1[1],color1[2]);
|
||||
else
|
||||
glColor3f (1,1,1);
|
||||
|
||||
glVertex3f (MPCurrent->m_pVertices[v1].m_Position.X,
|
||||
MPCurrent->m_pVertices[v1].m_Position.Y,
|
||||
MPCurrent->m_pVertices[v1].m_Position.Z);
|
||||
|
||||
glTexCoord2f (tu[1], tv[1]);
|
||||
|
||||
if (g_HillShading)
|
||||
glColor3f (color2[0],color2[1],color2[2]);
|
||||
else
|
||||
glColor3f (1,1,1);
|
||||
|
||||
glVertex3f (MPCurrent->m_pVertices[v2].m_Position.X,
|
||||
MPCurrent->m_pVertices[v2].m_Position.Y,
|
||||
MPCurrent->m_pVertices[v2].m_Position.Z);
|
||||
|
||||
tu[0]+=0.125f;
|
||||
tu[1]+=0.125f;
|
||||
}
|
||||
|
||||
MPCurrent->m_LastRenderedFrame = g_FrameCounter;
|
||||
MPCurrent->m_RenderStage = RENDER_STAGE_BASE;
|
||||
|
||||
if (!MPCurrent->m_pRightNeighbor)
|
||||
break;
|
||||
else
|
||||
{
|
||||
if (MPCurrent->m_pRightNeighbor->Tex1 != MPCurrent->Tex1 ||
|
||||
MPCurrent->m_pRightNeighbor->m_pParrent->m_LastVisFrame != g_FrameCounter)
|
||||
break;
|
||||
}
|
||||
|
||||
MPCurrent = MPCurrent->m_pRightNeighbor;
|
||||
start = 1;
|
||||
}
|
||||
|
||||
glEnd ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CRenderer::RenderPatchTrans (CPatch *patch)
|
||||
{
|
||||
CMiniPatch *MPatch, *MPCurrent;
|
||||
|
||||
float StartU, StartV;
|
||||
|
||||
glEnable (GL_BLEND);
|
||||
glDepthFunc (GL_EQUAL);
|
||||
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
for (int j=0; j<16; j++)
|
||||
{
|
||||
for (int i=0; i<16; i++)
|
||||
{
|
||||
MPatch = &(patch->m_MiniPatches[j][i]);
|
||||
|
||||
if (MPatch->m_LastRenderedFrame == g_FrameCounter &&
|
||||
MPatch->m_RenderStage == RENDER_STAGE_TRANS)
|
||||
continue;
|
||||
|
||||
//now for transition
|
||||
if (MPatch->Tex2 && MPatch->m_AlphaMap)
|
||||
{
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
tex_bind(MPatch->Tex2);
|
||||
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
/////////////////////////////////////
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
||||
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
/////////////////////////////////////
|
||||
|
||||
|
||||
glActiveTexture (GL_TEXTURE1);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
tex_bind(MPatch->m_AlphaMap);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
/////////////////////////////////////
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
||||
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
/////////////////////////////////////
|
||||
|
||||
StartU = 0.125f * (float)(i%8);
|
||||
StartV = 0.125f * (float)(j%8);
|
||||
|
||||
float tu[2], tv[2];
|
||||
tu[0] = tu[1] = StartU;
|
||||
tv[0] = StartV+0.125f;
|
||||
tv[1] = StartV;
|
||||
|
||||
glBegin (GL_TRIANGLE_STRIP);
|
||||
MPCurrent = MPatch;
|
||||
|
||||
int start = 0;
|
||||
|
||||
while (MPCurrent)
|
||||
{
|
||||
for (int x=start; x<2; x++)
|
||||
{
|
||||
int v1 = MAP_SIZE + x;
|
||||
int v2 = x;
|
||||
|
||||
float factor = m_Timer;
|
||||
if (m_CurrentSeason == 1)
|
||||
factor = 1.0f - factor;
|
||||
|
||||
float color1[3] = {MPCurrent->m_pVertices[v1].m_Color[0][0]*factor + MPCurrent->m_pVertices[v1].m_Color[1][0]*(1.0f-factor),
|
||||
MPCurrent->m_pVertices[v1].m_Color[0][1]*factor + MPCurrent->m_pVertices[v1].m_Color[1][1]*(1.0f-factor),
|
||||
MPCurrent->m_pVertices[v1].m_Color[0][2]*factor + MPCurrent->m_pVertices[v1].m_Color[1][2]*(1.0f-factor)};
|
||||
|
||||
float color2[3] = {MPCurrent->m_pVertices[v2].m_Color[0][0]*factor + MPCurrent->m_pVertices[v2].m_Color[1][0]*(1.0f-factor),
|
||||
MPCurrent->m_pVertices[v2].m_Color[0][1]*factor + MPCurrent->m_pVertices[v2].m_Color[1][1]*(1.0f-factor),
|
||||
MPCurrent->m_pVertices[v2].m_Color[0][2]*factor + MPCurrent->m_pVertices[v2].m_Color[1][2]*(1.0f-factor)};
|
||||
|
||||
glMultiTexCoord2f (GL_TEXTURE0_ARB, tu[0], tv[0]);
|
||||
glMultiTexCoord2f (GL_TEXTURE1_ARB, tu[0]*2, tv[0]*2);
|
||||
|
||||
if (g_HillShading)
|
||||
glColor3f (color1[0],color1[1],color1[2]);
|
||||
else
|
||||
glColor3f (1,1,1);
|
||||
|
||||
glVertex3f (MPCurrent->m_pVertices[v1].m_Position.X,
|
||||
MPCurrent->m_pVertices[v1].m_Position.Y,
|
||||
MPCurrent->m_pVertices[v1].m_Position.Z);
|
||||
|
||||
glMultiTexCoord2f (GL_TEXTURE0_ARB, tu[1], tv[1]);
|
||||
glMultiTexCoord2f (GL_TEXTURE1_ARB, tu[1]*2, tv[1]*2);
|
||||
|
||||
if (g_HillShading)
|
||||
glColor3f (color2[0],color2[1],color2[2]);
|
||||
else
|
||||
glColor3f (1,1,1);
|
||||
|
||||
glVertex3f (MPCurrent->m_pVertices[v2].m_Position.X,
|
||||
MPCurrent->m_pVertices[v2].m_Position.Y,
|
||||
MPCurrent->m_pVertices[v2].m_Position.Z);
|
||||
|
||||
tu[0]+=0.125f;
|
||||
tu[1]+=0.125f;
|
||||
}
|
||||
|
||||
MPCurrent->m_LastRenderedFrame = g_FrameCounter;
|
||||
MPCurrent->m_RenderStage = RENDER_STAGE_TRANS;
|
||||
|
||||
if (!MPCurrent->m_pRightNeighbor)
|
||||
break;
|
||||
else
|
||||
{
|
||||
if (MPCurrent->m_pRightNeighbor->Tex2 != MPCurrent->Tex2 ||
|
||||
MPCurrent->m_pRightNeighbor->m_AlphaMap != MPCurrent->m_AlphaMap ||
|
||||
MPCurrent->m_pRightNeighbor->m_pParrent->m_LastVisFrame != g_FrameCounter)
|
||||
break;
|
||||
}
|
||||
|
||||
MPCurrent = MPCurrent->m_pRightNeighbor;
|
||||
start=1;
|
||||
}
|
||||
|
||||
glEnd ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glDepthFunc (GL_LEQUAL);
|
||||
glDisable (GL_BLEND);
|
||||
glActiveTexture (GL_TEXTURE1);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void CRenderer::RenderTileOutline (CMiniPatch *mpatch)
|
||||
{
|
||||
if(!mpatch->m_pVertices)
|
||||
return;
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glDisable (GL_DEPTH_TEST);
|
||||
glDisable (GL_TEXTURE_2D);
|
||||
glLineWidth (4);
|
||||
|
||||
STerrainVertex V[4];
|
||||
V[0] = mpatch->m_pVertices[0];
|
||||
V[1] = mpatch->m_pVertices[1];
|
||||
V[2] = mpatch->m_pVertices[MAP_SIZE*1 + 1];
|
||||
V[3] = mpatch->m_pVertices[MAP_SIZE*1];
|
||||
|
||||
glColor3f (0,1.0f,0);
|
||||
|
||||
glBegin (GL_LINE_LOOP);
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
glVertex3fv(&V[i].m_Position.X);
|
||||
|
||||
glEnd ();
|
||||
|
||||
glEnable (GL_DEPTH_TEST);
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
}
|
40
source/terrain/Renderer.h
Executable file
40
source/terrain/Renderer.h
Executable file
@ -0,0 +1,40 @@
|
||||
#ifndef RENDERER_H
|
||||
#define RENDERER_H
|
||||
|
||||
#include <windows.h>
|
||||
#include "ogl.h"
|
||||
|
||||
#include "Terrain.H"
|
||||
|
||||
extern bool g_WireFrame;
|
||||
extern unsigned int g_FrameCounter;
|
||||
|
||||
class CRenderer
|
||||
{
|
||||
public:
|
||||
CRenderer();
|
||||
~CRenderer();
|
||||
|
||||
bool Initialize (HWND hwnd, int width, int height, int depth);
|
||||
void Shutdown ();
|
||||
|
||||
void RenderTerrain (CTerrain *terrain, CCamera *camera);
|
||||
void RenderTileOutline (CMiniPatch *mpatch);
|
||||
|
||||
protected:
|
||||
void RenderPatchBase (CPatch *patch);
|
||||
void RenderPatchTrans (CPatch *patch);
|
||||
|
||||
protected:
|
||||
int m_Width;
|
||||
int m_Height;
|
||||
int m_Depth;
|
||||
|
||||
///THERE ARE NOT SUPPOSED TO BE HERE
|
||||
float m_Timer;
|
||||
int m_CurrentSeason;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
29
source/terrain/TerrGlobals.h
Executable file
29
source/terrain/TerrGlobals.h
Executable file
@ -0,0 +1,29 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: TerrGlobals.H
|
||||
// Last Update: 27/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: Some globals and macros, used by the CTerrain
|
||||
// and CPatch
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef TERRGLOBALS_H
|
||||
#define TERRGLOBALS_H
|
||||
|
||||
const int PATCH_SIZE = 16;
|
||||
const int CELL_SIZE = 4; //horizontal scale of the patches
|
||||
const float HEIGHT_SCALE = 1.0f;
|
||||
|
||||
//only 3x3 patches loaded at a time
|
||||
const int NUM_PATCHES_PER_SIDE = 20;
|
||||
|
||||
//must be odd number of patches
|
||||
//#define TERRAIN_CHUNK_SIZE (PATCH_SIZE*NUM_PATCHES_PER_SIDE)
|
||||
const int MAP_SIZE = ( (NUM_PATCHES_PER_SIDE*PATCH_SIZE)+1 );
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
192
source/terrain/Terrain.cpp
Executable file
192
source/terrain/Terrain.cpp
Executable file
@ -0,0 +1,192 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Terrain.Cpp
|
||||
// Last Update: 23/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: CTerrain handles the terrain portion of the
|
||||
// engine. It holds open the file to the terrain
|
||||
// information, so terrain data can be loaded
|
||||
// dynamically. We use a ROAM method to render
|
||||
// the terrain, ie using binary triangle trees.
|
||||
// The terrain consists of smaller PATCHS, which
|
||||
// do most of the work.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#include "Terrain.H"
|
||||
#include "tex.h"
|
||||
|
||||
bool g_HillShading = true;
|
||||
|
||||
CVector3D SeasonLight[2];
|
||||
float SeasonColor[2][3];
|
||||
|
||||
CTerrain::CTerrain ()
|
||||
{
|
||||
m_pVertices = NULL;
|
||||
}
|
||||
|
||||
CTerrain::~CTerrain ()
|
||||
{
|
||||
delete [] m_pVertices;
|
||||
}
|
||||
|
||||
bool CTerrain::Initalize (char *filename)
|
||||
{
|
||||
SeasonLight[0].Set (3, -1, 3);
|
||||
SeasonLight[0].Normalize();
|
||||
SeasonColor[0][0] = 0.8f; SeasonColor[0][1] = 1.0f; SeasonColor[0][2] = 0.8f;
|
||||
|
||||
SeasonLight[1].Set (2, -1, -3);
|
||||
SeasonLight[1].Normalize();
|
||||
SeasonColor[1][0] = 1.0f; SeasonColor[1][1] = 0.9f; SeasonColor[1][2] = 0.9f;
|
||||
|
||||
TEX tex;
|
||||
Handle h = tex_load(filename, &tex);
|
||||
if(!h)
|
||||
return false;
|
||||
const u8* data = tex.ptr;
|
||||
|
||||
m_pVertices = new STerrainVertex[MAP_SIZE*MAP_SIZE];
|
||||
if (m_pVertices == NULL)
|
||||
return false;
|
||||
|
||||
for (int j=0; j<MAP_SIZE; j++)
|
||||
{
|
||||
for (int i=0; i<MAP_SIZE; i++)
|
||||
{
|
||||
int pos = j*MAP_SIZE + i;
|
||||
|
||||
m_pVertices[pos].m_Position.X = ((float)i)*CELL_SIZE;
|
||||
m_pVertices[pos].m_Position.Y = (*data++)*0.35f;
|
||||
m_pVertices[pos].m_Position.Z = ((float)j)*CELL_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
for (j=0; j<NUM_PATCHES_PER_SIDE; j++)
|
||||
{
|
||||
for (int i=0; i<NUM_PATCHES_PER_SIDE; i++)
|
||||
{
|
||||
int pos = j*MAP_SIZE*PATCH_SIZE;
|
||||
pos += i*PATCH_SIZE;
|
||||
|
||||
m_Patches[j][i].Initialize ( &(m_pVertices[pos]) );
|
||||
}
|
||||
}
|
||||
|
||||
CalcLighting();
|
||||
SetNeighbors();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CTerrain::CalcLighting ()
|
||||
{
|
||||
CVector3D left, right, up, down, n[4];
|
||||
|
||||
for (int j=0; j<MAP_SIZE; j++)
|
||||
{
|
||||
for (int i=0; i<MAP_SIZE; i++)
|
||||
{
|
||||
left.Clear();
|
||||
right.Clear();
|
||||
up.Clear();
|
||||
down.Clear();
|
||||
|
||||
if (i>0)
|
||||
left = m_pVertices[j*MAP_SIZE + i - 1].m_Position -
|
||||
m_pVertices[j*MAP_SIZE + i].m_Position;
|
||||
|
||||
if (i<MAP_SIZE-1)
|
||||
right = m_pVertices[j*MAP_SIZE + i + 1].m_Position -
|
||||
m_pVertices[j*MAP_SIZE + i].m_Position;
|
||||
|
||||
if (j>0)
|
||||
up = m_pVertices[(j-1)*MAP_SIZE + i].m_Position -
|
||||
m_pVertices[j*MAP_SIZE + i].m_Position;
|
||||
|
||||
if (j<MAP_SIZE-1)
|
||||
down = m_pVertices[(j+1)*MAP_SIZE + i].m_Position -
|
||||
m_pVertices[j*MAP_SIZE + i].m_Position;
|
||||
|
||||
n[0] = up.Cross(left);
|
||||
n[1] = left.Cross(down);
|
||||
n[2] = down.Cross(right);
|
||||
n[3] = right.Cross(up);
|
||||
|
||||
n[0].Normalize();
|
||||
n[1].Normalize();
|
||||
n[2].Normalize();
|
||||
n[3].Normalize();
|
||||
|
||||
CVector3D Normal = n[0] + n[1] + n[2] + n[3];
|
||||
Normal.Normalize();
|
||||
|
||||
float Color1 = Normal.Dot(SeasonLight[0]*-1)/(Normal.GetLength() * SeasonLight[0].GetLength());
|
||||
Color1 = (Color1+1.0f)/1.4f;
|
||||
|
||||
if (Color1>1.0f)
|
||||
Color1=1.0f;
|
||||
if (Color1<0.0f)
|
||||
Color1=0.0f;
|
||||
|
||||
float Color2 = Normal.Dot(SeasonLight[1]*-1)/(Normal.GetLength() * SeasonLight[1].GetLength());
|
||||
Color2 = (Color2+1.0f)/1.4f;
|
||||
|
||||
if (Color2>1.0f)
|
||||
Color2=1.0f;
|
||||
if (Color2<0.0f)
|
||||
Color2=0.0f;
|
||||
|
||||
m_pVertices[j*MAP_SIZE + i].m_Color[0][0] = Color1*SeasonColor[0][0];
|
||||
m_pVertices[j*MAP_SIZE + i].m_Color[0][1] = Color1*SeasonColor[0][1];
|
||||
m_pVertices[j*MAP_SIZE + i].m_Color[0][2] = Color1*SeasonColor[0][2];
|
||||
|
||||
m_pVertices[j*MAP_SIZE + i].m_Color[1][0] = Color2*SeasonColor[1][0];
|
||||
m_pVertices[j*MAP_SIZE + i].m_Color[1][1] = Color2*SeasonColor[1][1];
|
||||
m_pVertices[j*MAP_SIZE + i].m_Color[1][2] = Color2*SeasonColor[1][2];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CTerrain::SetNeighbors ()
|
||||
{
|
||||
CPatch *ThisPatch, *RightPatch;
|
||||
|
||||
for (int pj=0; pj<NUM_PATCHES_PER_SIDE; pj++)
|
||||
{
|
||||
for (int pi=0; pi<NUM_PATCHES_PER_SIDE; pi++)
|
||||
{
|
||||
ThisPatch = &m_Patches[pj][pi];
|
||||
|
||||
if (pi < NUM_PATCHES_PER_SIDE-1)
|
||||
RightPatch = &m_Patches[pj][pi+1];
|
||||
else
|
||||
RightPatch = NULL;
|
||||
|
||||
|
||||
for (int tj=0; tj<16; tj++)
|
||||
{
|
||||
for (int ti=0; ti<16; ti++)
|
||||
{
|
||||
CMiniPatch *MPatch = &ThisPatch->m_MiniPatches[tj][ti];
|
||||
|
||||
MPatch->m_pParrent = ThisPatch;
|
||||
|
||||
if (ti < 15)
|
||||
MPatch->m_pRightNeighbor = &ThisPatch->m_MiniPatches[tj][ti+1];
|
||||
else
|
||||
{
|
||||
if (RightPatch)
|
||||
MPatch->m_pRightNeighbor = &RightPatch->m_MiniPatches[tj][0];
|
||||
else
|
||||
MPatch->m_pRightNeighbor = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
46
source/terrain/Terrain.h
Executable file
46
source/terrain/Terrain.h
Executable file
@ -0,0 +1,46 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Terrain.H
|
||||
// Last Update: 23/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: CTerrain handles the terrain portion of the
|
||||
// engine. It holds open the file to the terrain
|
||||
// information, so terrain data can be loaded
|
||||
// dynamically. We use a ROAM method to render
|
||||
// the terrain, ie using binary triangle trees.
|
||||
// The terrain consists of smaller PATCHS, which
|
||||
// do most of the work.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef TERRAIN_H
|
||||
#define TERRAIN_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Patch.H"
|
||||
#include "Vector3D.H"
|
||||
|
||||
extern bool g_HillShading;
|
||||
|
||||
class CTerrain
|
||||
{
|
||||
public:
|
||||
CTerrain ();
|
||||
~CTerrain ();
|
||||
|
||||
bool Initalize (char *filename);
|
||||
|
||||
// protected:
|
||||
//the patches currently loaded
|
||||
CPatch m_Patches[NUM_PATCHES_PER_SIDE][NUM_PATCHES_PER_SIDE];
|
||||
STerrainVertex *m_pVertices;
|
||||
|
||||
|
||||
// protected:
|
||||
void CalcLighting();
|
||||
void SetNeighbors();
|
||||
};
|
||||
|
||||
#endif
|
88
source/terrain/Types.h
Executable file
88
source/terrain/Types.h
Executable file
@ -0,0 +1,88 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Types.H
|
||||
// Last Update: 25/1/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: The basic types used by the engine
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//basic return types
|
||||
enum FRESULT
|
||||
{
|
||||
R_OK = 0,
|
||||
R_FAIL, //use if nothing else matches the return type
|
||||
|
||||
R_BADPARAMS, //one or more of the parameters were invalid
|
||||
|
||||
R_NOMEMORY, //not enough memory for an operation
|
||||
|
||||
R_FILE_NOOPEN, //file could not be opened
|
||||
R_FILE_NOREAD, //file could not be read
|
||||
R_FILE_INVALID //file is corrupt or not supported
|
||||
};
|
||||
|
||||
//string related
|
||||
#define MAX_NAME_LENGTH (50)
|
||||
#define MAX_PATH_LENGTH (100)
|
||||
|
||||
//color structures
|
||||
struct SColor4ub
|
||||
{
|
||||
unsigned char R;
|
||||
unsigned char G;
|
||||
unsigned char B;
|
||||
unsigned char A;
|
||||
};
|
||||
|
||||
struct SColor4f
|
||||
{
|
||||
float R;
|
||||
float G;
|
||||
float B;
|
||||
float A;
|
||||
};
|
||||
|
||||
//all the major classes:
|
||||
class CBitmap;
|
||||
|
||||
class CCamera;
|
||||
|
||||
class CDiesel3DVertex;
|
||||
|
||||
class CGameResource;
|
||||
|
||||
class CEngine;
|
||||
class CEntity;
|
||||
|
||||
class CFrustum;
|
||||
|
||||
class CMatrix3D;
|
||||
class CMesh;
|
||||
class CMeshPoly;
|
||||
class CShadyMesh;
|
||||
class CShadyMeshPoly;
|
||||
|
||||
class CNode;
|
||||
|
||||
class CPatch;
|
||||
class CPlane;
|
||||
|
||||
class CRenderer;
|
||||
|
||||
class CTerrain;
|
||||
class CTexture;
|
||||
|
||||
class CVector3D;
|
||||
|
||||
class CWorld;
|
||||
|
||||
|
||||
#endif
|
181
source/terrain/Vector3D.cpp
Executable file
181
source/terrain/Vector3D.cpp
Executable file
@ -0,0 +1,181 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Vector3D.Cpp
|
||||
// Last Update: 28/1/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: Provides an interface for a vector in R3 and
|
||||
// allows vector and scalar operations on it
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#include "Vector3D.H"
|
||||
|
||||
CVector3D::CVector3D ()
|
||||
{
|
||||
X = Y = Z = 0.0f;
|
||||
}
|
||||
|
||||
CVector3D::CVector3D (float x, float y, float z)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
}
|
||||
|
||||
int CVector3D::operator == (CVector3D &vector)
|
||||
{
|
||||
if (X != vector.X ||
|
||||
Y != vector.Y ||
|
||||
Z != vector.Z)
|
||||
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CVector3D::operator != (CVector3D &vector)
|
||||
{
|
||||
if (X != vector.X ||
|
||||
Y != vector.Y ||
|
||||
Z != vector.Z)
|
||||
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CVector3D::operator ! ()
|
||||
{
|
||||
if (X != 0.0f ||
|
||||
Y != 0.0f ||
|
||||
Z != 0.0f)
|
||||
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//vector addition
|
||||
CVector3D CVector3D::operator + (CVector3D &vector)
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = X + vector.X;
|
||||
Temp.Y = Y + vector.Y;
|
||||
Temp.Z = Z + vector.Z;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//vector addition/assignment
|
||||
CVector3D &CVector3D::operator += (CVector3D &vector)
|
||||
{
|
||||
X += vector.X;
|
||||
Y += vector.Y;
|
||||
Z += vector.Z;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//vector subtraction
|
||||
CVector3D CVector3D::operator - (CVector3D &vector)
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = X - vector.X;
|
||||
Temp.Y = Y - vector.Y;
|
||||
Temp.Z = Z - vector.Z;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//vector subtrcation/assignment
|
||||
CVector3D &CVector3D::operator -= (CVector3D &vector)
|
||||
{
|
||||
X -= vector.X;
|
||||
Y -= vector.Y;
|
||||
Z -= vector.Z;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//scalar multiplication
|
||||
CVector3D CVector3D::operator * (float value)
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = X * value;
|
||||
Temp.Y = Y * value;
|
||||
Temp.Z = Z * value;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//scalar multiplication/assignment
|
||||
CVector3D CVector3D::operator *= (float value)
|
||||
{
|
||||
X *= value;
|
||||
Y *= value;
|
||||
Z *= value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CVector3D::Set (float x, float y, float z)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
}
|
||||
|
||||
void CVector3D::Clear ()
|
||||
{
|
||||
X = Y = Z = 0.0f;
|
||||
}
|
||||
|
||||
//Dot product
|
||||
float CVector3D::Dot (CVector3D &vector)
|
||||
{
|
||||
return ( X * vector.X +
|
||||
Y * vector.Y +
|
||||
Z * vector.Z );
|
||||
}
|
||||
|
||||
//Cross product
|
||||
CVector3D CVector3D::Cross (CVector3D &vector)
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = (Y * vector.Z) - (Z * vector.Y);
|
||||
Temp.Y = (Z * vector.X) - (X * vector.Z);
|
||||
Temp.Z = (X * vector.Y) - (Y * vector.X);
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
float CVector3D::GetLength ()
|
||||
{
|
||||
return sqrtf ( SQR(X) + SQR(Y) + SQR(Z) );
|
||||
}
|
||||
|
||||
void CVector3D::Normalize ()
|
||||
{
|
||||
float scale = 1.0f/GetLength ();
|
||||
|
||||
X *= scale;
|
||||
Y *= scale;
|
||||
Z *= scale;
|
||||
}
|
||||
|
||||
SColor4ub CVector3D::ConvertToColor (float alpha_factor)
|
||||
{
|
||||
SColor4ub color;
|
||||
|
||||
color.R = (unsigned char)(127.0f * X + 128.0f);
|
||||
color.G = (unsigned char)(127.0f * Y + 128.0f);
|
||||
color.B = (unsigned char)(127.0f * Z + 128.0f);
|
||||
color.A = (unsigned char)(255.0f * alpha_factor);
|
||||
|
||||
return color;
|
||||
}
|
65
source/terrain/Vector3D.h
Executable file
65
source/terrain/Vector3D.h
Executable file
@ -0,0 +1,65 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Vector3D.H
|
||||
// Last Update: 28/1/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: Provides an interface for a vector in R3 and
|
||||
// allows vector and scalar operations on it
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef VECTOR3D_H
|
||||
#define VECTOR3D_H
|
||||
|
||||
#include <math.h>
|
||||
#include "MathUtil.H"
|
||||
#include "Types.H"
|
||||
|
||||
class CVector3D
|
||||
{
|
||||
public:
|
||||
float X, Y, Z;
|
||||
|
||||
public:
|
||||
CVector3D ();
|
||||
CVector3D (float x, float y, float z);
|
||||
|
||||
int operator == (CVector3D &vector);
|
||||
int operator != (CVector3D &vector);
|
||||
int operator ! ();
|
||||
|
||||
//vector addition
|
||||
CVector3D operator + (CVector3D &vector);
|
||||
//vector addition/assignment
|
||||
CVector3D &operator += (CVector3D &vector);
|
||||
|
||||
//vector subtraction
|
||||
CVector3D operator - (CVector3D &vector);
|
||||
//vector subtraction/assignment
|
||||
CVector3D &operator -= (CVector3D &vector);
|
||||
|
||||
//scalar multiplication
|
||||
CVector3D operator * (float value);
|
||||
//scalar multiplication/assignment
|
||||
CVector3D operator *= (float value);
|
||||
|
||||
public:
|
||||
void Set (float x, float y, float z);
|
||||
void Clear ();
|
||||
|
||||
//Dot product
|
||||
float Dot (CVector3D &vector);
|
||||
//Cross product
|
||||
CVector3D Cross (CVector3D &vector);
|
||||
|
||||
//Returns length of the vector
|
||||
float GetLength ();
|
||||
void Normalize ();
|
||||
|
||||
//Returns a color which describes the vector
|
||||
SColor4ub ConvertToColor (float alpha_factor);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
340
source/terrain/terrainMain.cpp
Executable file
340
source/terrain/terrainMain.cpp
Executable file
@ -0,0 +1,340 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "Matrix3D.H"
|
||||
#include "Renderer.H"
|
||||
#include "Terrain.H"
|
||||
|
||||
#include "time.h"
|
||||
#include "wsdl.h"
|
||||
#include "tex.h"
|
||||
|
||||
|
||||
HWND InitializeGame (HINSTANCE hInstance);
|
||||
void DestroyGame();
|
||||
|
||||
void InitScene ();
|
||||
void InitResources ();
|
||||
void RenderScene ();
|
||||
|
||||
extern bool keys[256];
|
||||
|
||||
|
||||
HWND GameWindow;
|
||||
|
||||
CMatrix3D g_WorldMat;
|
||||
CRenderer g_Renderer;
|
||||
CTerrain g_Terrain;
|
||||
CCamera g_Camera;
|
||||
|
||||
int SelPX, SelPY, SelTX, SelTY;
|
||||
int g_BaseTexCounter = 0;
|
||||
int g_SecTexCounter = 1;
|
||||
int g_TransTexCounter = 0;
|
||||
|
||||
int g_TickCounter = 0;
|
||||
double g_LastTime;
|
||||
|
||||
|
||||
const int NUM_ALPHA_MAPS = 13;
|
||||
|
||||
//CTexture g_BaseTexture[5];
|
||||
Handle BaseTexs[5];
|
||||
|
||||
Handle AlphaMaps[NUM_ALPHA_MAPS];
|
||||
//CTexture g_TransitionTexture[NUM_ALPHA_MAPS];
|
||||
|
||||
int mouse_x=50, mouse_y=50;
|
||||
|
||||
extern int xres, yres;
|
||||
|
||||
|
||||
void terr_init()
|
||||
{
|
||||
g_Renderer.Initialize (GameWindow, 1280, 1024, 32);
|
||||
|
||||
InitResources ();
|
||||
InitScene ();
|
||||
}
|
||||
|
||||
void terr_update()
|
||||
{
|
||||
g_FrameCounter++;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
POINT MousePos;
|
||||
|
||||
GetCursorPos (&MousePos);
|
||||
CVector3D right(1,0,1);
|
||||
CVector3D up(1,0,-1);
|
||||
right.Normalize ();
|
||||
up.Normalize ();
|
||||
|
||||
if (mouse_x >= xres-2)
|
||||
g_Camera.m_Orientation.Translate (right);
|
||||
if (mouse_x <= 3)
|
||||
g_Camera.m_Orientation.Translate (right*-1);
|
||||
|
||||
if (mouse_y >= yres-2)
|
||||
g_Camera.m_Orientation.Translate (up);
|
||||
if (mouse_y <= 3)
|
||||
g_Camera.m_Orientation.Translate (up*-1);
|
||||
|
||||
|
||||
|
||||
float fov = g_Camera.GetFOV();
|
||||
float d = DEGTORAD(0.4f);
|
||||
if(keys[SDLK_KP_MINUS])
|
||||
if (fov+d < DEGTORAD(90))
|
||||
g_Camera.SetProjection (1, 1000, fov + d);
|
||||
if(keys[SDLK_KP_ADD])
|
||||
if (fov-d > DEGTORAD(20))
|
||||
g_Camera.SetProjection (1, 1000, fov - d);
|
||||
|
||||
g_Camera.UpdateFrustum ();
|
||||
/////////////////////////////////////////////
|
||||
|
||||
|
||||
g_Renderer.RenderTerrain (&g_Terrain, &g_Camera);
|
||||
g_Renderer.RenderTileOutline (&(g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX]));
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool terr_handler(const SDL_Event& ev)
|
||||
{
|
||||
switch(ev.type)
|
||||
{
|
||||
case SDL_MOUSEMOTION:
|
||||
mouse_x = ev.motion.x;
|
||||
mouse_y = ev.motion.y;
|
||||
break;
|
||||
|
||||
case SDL_KEYDOWN:
|
||||
switch(ev.key.keysym.sym)
|
||||
{
|
||||
case 'W':
|
||||
g_WireFrame = !g_WireFrame;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
// quick hack to return camera home, for screenshots (after alt+tabbing)
|
||||
g_Camera.SetProjection (1, 1000, DEGTORAD(20));
|
||||
g_Camera.m_Orientation.SetXRotation(DEGTORAD(30));
|
||||
g_Camera.m_Orientation.RotateY(DEGTORAD(-45));
|
||||
g_Camera.m_Orientation.Translate (100, 150, -100);
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
g_HillShading = !g_HillShading;
|
||||
break;
|
||||
|
||||
// tile selection
|
||||
case SDLK_DOWN:
|
||||
if(++SelTX > 15)
|
||||
if(SelPX == NUM_PATCHES_PER_SIDE-1)
|
||||
SelTX = 15;
|
||||
else
|
||||
SelTX = 0, SelPX++;
|
||||
break;
|
||||
|
||||
case SDLK_UP:
|
||||
if(--SelTX < 0)
|
||||
if(SelPX == 0)
|
||||
SelTX = 0;
|
||||
else
|
||||
SelTX = 15, SelPX--;
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
if(++SelTY > 15)
|
||||
if(SelPY == NUM_PATCHES_PER_SIDE-1)
|
||||
SelTY = 15;
|
||||
else
|
||||
SelTY = 0, SelPY++;
|
||||
break;
|
||||
|
||||
case SDLK_LEFT:
|
||||
if(--SelTY < 0)
|
||||
if(SelPY == 0)
|
||||
SelTY = 0;
|
||||
else
|
||||
SelTY = 15, SelPY--;
|
||||
break;
|
||||
|
||||
|
||||
case SDLK_KP0:
|
||||
{
|
||||
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX];
|
||||
if (!MPatch->Tex2)
|
||||
{
|
||||
MPatch->m_AlphaMap = AlphaMaps[g_TransTexCounter];
|
||||
MPatch->Tex2 = BaseTexs[g_SecTexCounter];
|
||||
}
|
||||
else
|
||||
{
|
||||
MPatch->Tex2 = 0;
|
||||
MPatch->m_AlphaMap = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SDLK_KP1:
|
||||
{
|
||||
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX];
|
||||
|
||||
g_BaseTexCounter++;
|
||||
if (g_BaseTexCounter > 4)
|
||||
g_BaseTexCounter = 0;
|
||||
|
||||
MPatch->Tex1 = BaseTexs[g_BaseTexCounter];
|
||||
break;
|
||||
}
|
||||
|
||||
case SDLK_KP2:
|
||||
{
|
||||
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX];
|
||||
|
||||
if (MPatch->Tex2)
|
||||
{
|
||||
g_SecTexCounter++;
|
||||
if (g_SecTexCounter > 4)
|
||||
g_SecTexCounter = 0;
|
||||
|
||||
MPatch->Tex2 = BaseTexs[g_SecTexCounter];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SDLK_KP3:
|
||||
{
|
||||
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX];
|
||||
|
||||
if (MPatch->/*m_pTransitionTexture*/m_AlphaMap)
|
||||
{
|
||||
g_TransTexCounter++;
|
||||
if (g_TransTexCounter >= NUM_ALPHA_MAPS)
|
||||
g_TransTexCounter = 0;
|
||||
|
||||
MPatch->m_AlphaMap = AlphaMaps[g_TransTexCounter];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void InitScene ()
|
||||
{
|
||||
g_Terrain.Initalize ("terrain.raw");
|
||||
|
||||
for (int pj=0; pj<NUM_PATCHES_PER_SIDE; pj++)
|
||||
{
|
||||
for (int pi=0; pi<NUM_PATCHES_PER_SIDE; pi++)
|
||||
{
|
||||
for (int tj=0; tj<16; tj++)
|
||||
{
|
||||
for (int ti=0; ti<16; ti++)
|
||||
{
|
||||
g_Terrain.m_Patches[pj][pi].m_MiniPatches[tj][ti].Tex1 = BaseTexs[0];//rand()%5];
|
||||
g_Terrain.m_Patches[pj][pi].m_MiniPatches[tj][ti].Tex2 = NULL;//&g_BaseTexture[rand()%5];
|
||||
g_Terrain.m_Patches[pj][pi].m_MiniPatches[tj][ti].m_AlphaMap = 0;//&g_TransitionTexture[rand()%5];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_Camera.SetProjection (1, 1000, DEGTORAD(20));
|
||||
g_Camera.m_Orientation.SetXRotation(DEGTORAD(30));
|
||||
g_Camera.m_Orientation.RotateY(DEGTORAD(-45));
|
||||
|
||||
g_Camera.m_Orientation.Translate (100, 150, -100);
|
||||
|
||||
SelPX = SelPY = SelTX = SelTY = 0;
|
||||
}
|
||||
|
||||
void InitResources()
|
||||
{
|
||||
int i;
|
||||
char* base_fns[] =
|
||||
{
|
||||
"Base1.bmp",
|
||||
"Base2.bmp",
|
||||
"Base3.bmp",
|
||||
"Base4.bmp",
|
||||
"Base5.bmp"
|
||||
};
|
||||
|
||||
for(i = 0; i < 5; i++)
|
||||
{
|
||||
BaseTexs[i] = tex_load(base_fns[i]);
|
||||
tex_upload(BaseTexs[i], GL_LINEAR_MIPMAP_LINEAR);
|
||||
}
|
||||
|
||||
|
||||
int cnt;
|
||||
#if 1
|
||||
|
||||
char* fns[NUM_ALPHA_MAPS] = {
|
||||
"blendcircle.raw",
|
||||
"blendcorner.raw",
|
||||
"blendedge.raw",
|
||||
"blendedgecorner.raw",
|
||||
"blendedgetwocorners.raw",
|
||||
"blendfourcorners.raw",
|
||||
"blendlshape.raw",
|
||||
"blendlshapecorner.raw",
|
||||
"blendthreecorners.raw",
|
||||
"blendtwocorners.raw",
|
||||
"blendtwoedges.raw",
|
||||
"blendtwooppositecorners.raw",
|
||||
"blendushape.raw"
|
||||
};
|
||||
/*
|
||||
//for(i = 0; i < NUM_ALPHA_MAPS;i++)
|
||||
i=5;
|
||||
{
|
||||
FILE* f = fopen(fns[i],"rb");
|
||||
u8 buf[5000],buf2[5000];
|
||||
fread(buf,5000,1,f);
|
||||
fclose(f);
|
||||
for(int j = 0; j < 1024; j++)
|
||||
buf2[2*j] = buf2[2*j+1] = buf[j];
|
||||
f=fopen(fns[i],"wb");
|
||||
fwrite(buf2,2048,1,f);
|
||||
fclose(f);
|
||||
}
|
||||
/**/
|
||||
cnt=13;
|
||||
#else
|
||||
|
||||
char* fns[NUM_ALPHA_MAPS] = {
|
||||
"Transition1.bmp",
|
||||
"Transition2.bmp",
|
||||
"Transition3.bmp",
|
||||
"Transition4.bmp",
|
||||
"Transition5.bmp",
|
||||
};
|
||||
cnt=5;
|
||||
#endif
|
||||
|
||||
for(i = 0; i < cnt; i++)
|
||||
{
|
||||
AlphaMaps[i] = tex_load(fns[i]);
|
||||
tex_upload(AlphaMaps[i], GL_LINEAR, GL_INTENSITY4);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user