You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
756 lines
23 KiB
C++
756 lines
23 KiB
C++
/*
|
|
OpenMW - The completely unofficial reimplementation of Morrowind
|
|
Copyright (C) 2008 Nicolay Korslund
|
|
Email: < korslund@gmail.com >
|
|
WWW: http://openmw.snaptoad.com/
|
|
|
|
This file (cpp_interface.cpp) is part of the OpenMW package.
|
|
|
|
OpenMW is distributed as free software: you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License
|
|
version 3, as published by the Free Software Foundation.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
version 3 along with this program. If not, see
|
|
http://www.gnu.org/licenses/ .
|
|
|
|
*/
|
|
|
|
//-----------------------------------------------------------------------
|
|
// E X P O R T E D F U N C T I O N S
|
|
//-----------------------------------------------------------------------
|
|
|
|
extern "C" void cpp_cleanup()
|
|
{
|
|
// Kill the input systems. This will reset input options such as key
|
|
// repetition.
|
|
mInputManager->destroyInputObject(mKeyboard);
|
|
mInputManager->destroyInputObject(mMouse);
|
|
OIS::InputManager::destroyInputSystem(mInputManager);
|
|
|
|
// Kill OGRE
|
|
if (mRoot)
|
|
{
|
|
delete mRoot;
|
|
mRoot = 0;
|
|
}
|
|
}
|
|
|
|
extern "C" int cpp_configure()
|
|
{
|
|
mRoot = new Root();
|
|
|
|
// Add the BSA archive manager before reading the config file.
|
|
ArchiveManager::getSingleton().addArchiveFactory( &mBSAFactory );
|
|
|
|
// Load resource paths from config file
|
|
ConfigFile cf;
|
|
cf.load("resources.cfg");
|
|
|
|
// Go through all sections & settings in the file
|
|
ConfigFile::SectionIterator seci = cf.getSectionIterator();
|
|
|
|
String secName, typeName, archName;
|
|
while (seci.hasMoreElements())
|
|
{
|
|
secName = seci.peekNextKey();
|
|
ConfigFile::SettingsMultiMap *settings = seci.getNext();
|
|
ConfigFile::SettingsMultiMap::iterator i;
|
|
for (i = settings->begin(); i != settings->end(); ++i)
|
|
{
|
|
typeName = i->first;
|
|
archName = i->second;
|
|
ResourceGroupManager::getSingleton().addResourceLocation(
|
|
archName, typeName, secName);
|
|
}
|
|
}
|
|
|
|
// Show the configuration dialog and initialise the system
|
|
// You can skip this and use root.restoreConfig() to load configuration
|
|
// settings if you were sure there are valid ones saved in ogre.cfg
|
|
|
|
//if(mRoot->showConfigDialog())
|
|
if(mRoot->restoreConfig())
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
// Initialize window. This will create and show the actual window.
|
|
extern "C" void cpp_initWindow()
|
|
{
|
|
std::cout << "cpp_initWindow()\n";
|
|
|
|
// Initialize OGRE.
|
|
mWindow = mRoot->initialise(true);
|
|
|
|
// Set up the input system
|
|
|
|
using namespace OIS;
|
|
|
|
size_t windowHnd;
|
|
mWindow->getCustomAttribute("WINDOW", &windowHnd);
|
|
|
|
std::ostringstream windowHndStr;
|
|
ParamList pl;
|
|
|
|
windowHndStr << windowHnd;
|
|
pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
|
|
|
|
// Non-exclusive mouse and keyboard input
|
|
/*
|
|
#if defined OIS_WIN32_PLATFORM
|
|
pl.insert(std::make_pair(std::string("w32_mouse"),
|
|
std::string("DISCL_FOREGROUND" )));
|
|
pl.insert(std::make_pair(std::string("w32_mouse"),
|
|
std::string("DISCL_NONEXCLUSIVE")));
|
|
pl.insert(std::make_pair(std::string("w32_keyboard"),
|
|
std::string("DISCL_FOREGROUND")));
|
|
pl.insert(std::make_pair(std::string("w32_keyboard"),
|
|
std::string("DISCL_NONEXCLUSIVE")));
|
|
#elif defined OIS_LINUX_PLATFORM
|
|
pl.insert(std::make_pair(std::string("x11_mouse_grab"),
|
|
std::string("true")));
|
|
pl.insert(std::make_pair(std::string("x11_mouse_hide"),
|
|
std::string("true")));
|
|
pl.insert(std::make_pair(std::string("x11_keyboard_grab"),
|
|
std::string("true")));
|
|
pl.insert(std::make_pair(std::string("XAutoRepeatOn"),
|
|
std::string("false")));
|
|
#endif
|
|
*/
|
|
|
|
mInputManager = InputManager::createInputSystem( pl );
|
|
|
|
const bool bufferedKeys = true;
|
|
const bool bufferedMouse = true;
|
|
|
|
// Create all devices
|
|
mKeyboard = static_cast<Keyboard*>(mInputManager->createInputObject
|
|
( OISKeyboard, bufferedKeys ));
|
|
mMouse = static_cast<Mouse*>(mInputManager->createInputObject
|
|
( OISMouse, bufferedMouse ));
|
|
|
|
unsigned int width, height, depth;
|
|
int left, top;
|
|
mWindow->getMetrics(width, height, depth, left, top);
|
|
|
|
// Set mouse region
|
|
const MouseState &ms = mMouse->getMouseState();
|
|
ms.width = width;
|
|
ms.height = height;
|
|
|
|
// Register the input listener
|
|
mKeyboard -> setEventCallback( &mInput );
|
|
mMouse -> setEventCallback( &mInput );
|
|
|
|
std::cout << "cpp_initWindow finished\n";
|
|
}
|
|
|
|
// Make a scene, set the given ambient light
|
|
extern "C" void cpp_makeScene()
|
|
{
|
|
// Get the SceneManager, in this case a generic one
|
|
mSceneMgr = mRoot->createSceneManager(ST_GENERIC);
|
|
|
|
// Create the camera
|
|
mCamera = mSceneMgr->createCamera("PlayerCam");
|
|
|
|
mCamera->setNearClipDistance(5);
|
|
|
|
// Create one viewport, entire window
|
|
vp = mWindow->addViewport(mCamera);
|
|
// Give the backround a healthy shade of green
|
|
vp->setBackgroundColour(ColourValue(0,0.1,0));
|
|
|
|
// Alter the camera aspect ratio to match the viewport
|
|
mCamera->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
|
|
|
|
// Set default mipmap level (NB some APIs ignore this)
|
|
TextureManager::getSingleton().setDefaultNumMipmaps(5);
|
|
|
|
// Load resources
|
|
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
|
|
|
|
// Add the frame listener
|
|
mRoot->addFrameListener(&mFrameListener);
|
|
|
|
// Turn the entire scene (represented by the 'root' node) -90
|
|
// degrees around the x axis. This makes Z go upwards, and Y go into
|
|
// the screen. This is the orientation that Morrowind uses, and it
|
|
// automagically makes everything work as it should.
|
|
SceneNode *rt = mSceneMgr->getRootSceneNode();
|
|
root = rt->createChildSceneNode();
|
|
root->pitch(Degree(-90));
|
|
}
|
|
|
|
extern "C" void cpp_makeSky()
|
|
{
|
|
mSceneMgr->setSkyDome( true, "Examples/CloudySky", 5, 8 );
|
|
}
|
|
|
|
extern "C" Light* cpp_attachLight(char *name, SceneNode* base,
|
|
float r, float g, float b,
|
|
float radius)
|
|
{
|
|
Light *l = mSceneMgr->createLight(name);
|
|
|
|
l->setDiffuseColour(r,g,b);
|
|
|
|
// Pulled these numbers out of nowhere. Looks OK-ish. I can polish
|
|
// it later.
|
|
l->setAttenuation(8*radius, 0, 0.008, 0.0);
|
|
|
|
// base might be null, sometimes lights don't have meshes
|
|
if(base) base->attachObject(l);
|
|
|
|
return l;
|
|
}
|
|
|
|
extern "C" void cpp_setAmbient(float r, float g, float b, // Ambient light
|
|
float rs, float gs, float bs) // "Sunlight"
|
|
{
|
|
ColourValue c = ColourValue(r, g, b);
|
|
mSceneMgr->setAmbientLight(c);
|
|
|
|
// Create a "sun" that shines light downwards. It doesn't look
|
|
// completely right, but leave it for now.
|
|
Light *l = mSceneMgr->createLight("Sun");
|
|
l->setDiffuseColour(rs, gs, bs);
|
|
l->setType(Light::LT_DIRECTIONAL);
|
|
l->setDirection(0,-1,0);
|
|
}
|
|
|
|
extern "C" void cpp_setFog(float rf, float gf, float bf, // Fog color
|
|
float flow, float fhigh) // Fog distance
|
|
{
|
|
ColourValue fogColor( rf, gf, bf );
|
|
mSceneMgr->setFog( FOG_LINEAR, fogColor, 0.0, flow, fhigh );
|
|
|
|
// Don't render what you can't see anyway
|
|
mCamera->setFarClipDistance(fhigh + 10);
|
|
|
|
// Leave this out for now
|
|
//vp->setBackgroundColour(fogColor);
|
|
}
|
|
|
|
extern "C" void cpp_startRendering()
|
|
{
|
|
mRoot->startRendering();
|
|
}
|
|
|
|
// Copy a scene node and all its children
|
|
void cloneNode(SceneNode *from, SceneNode *to, char* name)
|
|
{
|
|
to->setPosition(from->getPosition());
|
|
to->setOrientation(from->getOrientation());
|
|
to->setScale(from->getScale());
|
|
|
|
SceneNode::ObjectIterator it = from->getAttachedObjectIterator();
|
|
while(it.hasMoreElements())
|
|
{
|
|
// We can't handle non-entities. To be honest I have no idea
|
|
// what dynamic_cast does or if it's correct here. I used to be
|
|
// a C++ person but after discovering D I dropped C++ like it
|
|
// was red hot iron and never looked back.
|
|
Entity *e = dynamic_cast<Entity*> (it.getNext());
|
|
if(e)
|
|
{
|
|
e = e->clone(String(name) + ":" + e->getName());
|
|
to->attachObject(e);
|
|
}
|
|
}
|
|
|
|
// Recursively clone all child nodes
|
|
SceneNode::ChildNodeIterator it2 = from->getChildIterator();
|
|
while(it2.hasMoreElements())
|
|
{
|
|
cloneNode((SceneNode*)it2.getNext(), to->createChildSceneNode(), name);
|
|
}
|
|
}
|
|
|
|
// Supposed to insert a copy of the node, for now it just inserts the
|
|
// actual node.
|
|
extern "C" SceneNode *cpp_insertNode(SceneNode *base, char* name,
|
|
float *pos, float scale)
|
|
{
|
|
//std::cout << "cpp_insertNode(" << name << ")\n";
|
|
SceneNode *node = root->createChildSceneNode(name);
|
|
|
|
// Make a copy of the node
|
|
cloneNode(base, node, name);
|
|
|
|
// pos points to a Placement struct, which has the format
|
|
// float x, y, z; // position
|
|
// float r1, r2, r3; // rotation
|
|
|
|
node->setPosition(pos[0], pos[1], pos[2]);
|
|
|
|
// Rotate around X axis
|
|
Quaternion xr(Radian(-pos[3]), Vector3::UNIT_X);
|
|
|
|
// Rotate around Y axis
|
|
Quaternion yr(Radian(-pos[4]), Vector3::UNIT_Y);
|
|
|
|
// Rotate around Z axis
|
|
Quaternion zr(Radian(-pos[5]), Vector3::UNIT_Z);
|
|
|
|
// Rotates first around z, then y, then x
|
|
node->setOrientation(xr*yr*zr);
|
|
|
|
node->setScale(scale, scale, scale);
|
|
|
|
return node;
|
|
}
|
|
|
|
// Create the water plane. It doesn't really resemble "water" yet
|
|
// though.
|
|
extern "C" void cpp_createWater(float level)
|
|
{
|
|
// Create a plane aligned with the xy-plane.
|
|
MeshManager::getSingleton().createPlane("water",
|
|
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
|
Plane(Vector3::UNIT_Z, level),
|
|
150000,150000
|
|
//,20,20,true,1,5,5,Vector3::UNIT_Z
|
|
);
|
|
Entity *ent = mSceneMgr->createEntity( "WaterEntity", "water" );
|
|
root->createChildSceneNode()->attachObject(ent);
|
|
ent->setCastShadows(false);
|
|
}
|
|
|
|
// Manual loader for meshes. Reloading individual meshes is too
|
|
// difficult, and not worth the trouble. Later I should make one
|
|
// loader for each NIF file, and whenever it is invoked it should
|
|
// somehow reload the entire file. How this is to be done when some of
|
|
// the meshes might be loaded and in use already, I have no
|
|
// idea. Let's just ignore it for now.
|
|
|
|
class MeshLoader : public ManualResourceLoader
|
|
{
|
|
public:
|
|
|
|
void loadResource(Resource *resource)
|
|
{
|
|
}
|
|
} dummyLoader;
|
|
|
|
// TODO/FIXME/DEBUG (MURDER/DEATH/KILL)
|
|
String LASTNAME;
|
|
|
|
// Load the contents of a mesh
|
|
extern "C" void cpp_createMesh(
|
|
char* name, // Name of the mesh
|
|
int numVerts, // Number of vertices
|
|
float* vertices, // Vertex list
|
|
float* normals, // Normal list
|
|
float* colors, // Vertex colors
|
|
float* uvs, // Texture coordinates
|
|
int numFaces, // Number of faces*3
|
|
unsigned short* faces, // Faces
|
|
float radius, // Bounding sphere
|
|
char* material, // Material
|
|
// Bounding box
|
|
float minX,float minY,float minZ,
|
|
float maxX,float maxY,float maxZ,
|
|
SceneNode *owner
|
|
)
|
|
{
|
|
//std::cerr << "Creating mesh " << name << "\n";
|
|
|
|
MeshPtr msh = MeshManager::getSingleton().createManual(name, "Meshes",
|
|
&dummyLoader);
|
|
|
|
Entity *e = mSceneMgr->createEntity(name, name);
|
|
|
|
owner->attachObject(e);
|
|
//msh->setSkeletonName(name);
|
|
|
|
// Create vertex data structure
|
|
msh->sharedVertexData = new VertexData();
|
|
msh->sharedVertexData->vertexCount = numVerts;
|
|
|
|
/// Create declaration (memory format) of vertex data
|
|
VertexDeclaration* decl = msh->sharedVertexData->vertexDeclaration;
|
|
|
|
int nextBuf = 0;
|
|
// 1st buffer
|
|
decl->addElement(nextBuf, 0, VET_FLOAT3, VES_POSITION);
|
|
|
|
/// Allocate vertex buffer of the requested number of vertices (vertexCount)
|
|
/// and bytes per vertex (offset)
|
|
HardwareVertexBufferSharedPtr vbuf =
|
|
HardwareBufferManager::getSingleton().createVertexBuffer(
|
|
VertexElement::getTypeSize(VET_FLOAT3),
|
|
numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
|
|
|
|
/// Upload the vertex data to the card
|
|
vbuf->writeData(0, vbuf->getSizeInBytes(), vertices, true);
|
|
|
|
/// Set vertex buffer binding so buffer 0 is bound to our vertex buffer
|
|
VertexBufferBinding* bind = msh->sharedVertexData->vertexBufferBinding;
|
|
bind->setBinding(nextBuf++, vbuf);
|
|
|
|
// The lists are read in the same order that they appear in NIF
|
|
// files, and likely in memory. Sequential reads might possibly
|
|
// avert an occational cache miss.
|
|
|
|
// normals
|
|
if(normals)
|
|
{
|
|
//std::cerr << "+ Adding normals\n";
|
|
decl->addElement(nextBuf, 0, VET_FLOAT3, VES_NORMAL);
|
|
vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
|
|
VertexElement::getTypeSize(VET_FLOAT3),
|
|
numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
|
|
|
|
vbuf->writeData(0, vbuf->getSizeInBytes(), normals, true);
|
|
|
|
bind->setBinding(nextBuf++, vbuf);
|
|
}
|
|
|
|
// vertex colors
|
|
if(colors)
|
|
{
|
|
//std::cerr << "+ Adding vertex colors\n";
|
|
// Use render system to convert colour value since colour packing varies
|
|
RenderSystem* rs = Root::getSingleton().getRenderSystem();
|
|
RGBA colorsRGB[numVerts];
|
|
RGBA *pColour = colorsRGB;
|
|
for(int i=0; i<numVerts; i++)
|
|
{
|
|
rs->convertColourValue(ColourValue(colors[0],colors[1],colors[2], colors[3]),
|
|
pColour++);
|
|
colors += 4;
|
|
}
|
|
|
|
decl->addElement(nextBuf, 0, VET_COLOUR, VES_DIFFUSE);
|
|
/// Allocate vertex buffer of the requested number of vertices (vertexCount)
|
|
/// and bytes per vertex (offset)
|
|
vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
|
|
VertexElement::getTypeSize(VET_COLOUR),
|
|
numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
|
|
/// Upload the vertex data to the card
|
|
vbuf->writeData(0, vbuf->getSizeInBytes(), colorsRGB, true);
|
|
|
|
/// Set vertex buffer binding so buffer 1 is bound to our colour buffer
|
|
bind->setBinding(nextBuf++, vbuf);
|
|
}
|
|
|
|
if(uvs)
|
|
{
|
|
//std::cerr << "+ Adding texture coordinates\n";
|
|
decl->addElement(nextBuf, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES);
|
|
vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
|
|
VertexElement::getTypeSize(VET_FLOAT2),
|
|
numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
|
|
|
|
vbuf->writeData(0, vbuf->getSizeInBytes(), uvs, true);
|
|
|
|
bind->setBinding(nextBuf++, vbuf);
|
|
}
|
|
|
|
// Create the submesh that holds triangle data
|
|
SubMesh* sub = msh->createSubMesh(name);
|
|
sub->useSharedVertices = true;
|
|
|
|
if(numFaces)
|
|
{
|
|
//std::cerr << "+ Adding faces\n";
|
|
/// Allocate index buffer of the requested number of faces
|
|
HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton().
|
|
createIndexBuffer(
|
|
HardwareIndexBuffer::IT_16BIT,
|
|
numFaces,
|
|
HardwareBuffer::HBU_STATIC_WRITE_ONLY);
|
|
|
|
/// Upload the index data to the card
|
|
ibuf->writeData(0, ibuf->getSizeInBytes(), faces, true);
|
|
|
|
/// Set parameters of the submesh
|
|
sub->indexData->indexBuffer = ibuf;
|
|
sub->indexData->indexCount = numFaces;
|
|
sub->indexData->indexStart = 0;
|
|
}
|
|
|
|
// Create a material with the given texture, if any.
|
|
|
|
// If this mesh has a material, attach it.
|
|
if(material) sub->setMaterialName(name);
|
|
|
|
/*
|
|
// Assign this submesh to the given bone
|
|
VertexBoneAssignment v;
|
|
v.boneIndex = ((Bone*)bone)->getHandle();
|
|
v.weight = 1.0;
|
|
|
|
std::cerr << "+ Assigning bone index " << v.boneIndex << "\n";
|
|
|
|
for(int i=0; i < numVerts; i++)
|
|
{
|
|
v.vertexIndex = i;
|
|
sub->addBoneAssignment(v);
|
|
}
|
|
*/
|
|
/// Set bounding information (for culling)
|
|
msh->_setBounds(AxisAlignedBox(minX,minY,minZ,maxX,maxY,maxZ));
|
|
|
|
//std::cerr << "+ Radius: " << radius << "\n";
|
|
msh->_setBoundingSphereRadius(radius);
|
|
}
|
|
|
|
extern "C" void cpp_createMaterial(char *name, // Name to give
|
|
// resource
|
|
|
|
float *ambient, // Ambient RBG
|
|
// value
|
|
float *diffuse,
|
|
float *specular,
|
|
float *emissive, // Self
|
|
// illumination
|
|
|
|
float glossiness,// Same as
|
|
// shininess?
|
|
|
|
float alpha, // Use this in all
|
|
// alpha values?
|
|
|
|
char* texture) // Texture
|
|
{
|
|
MaterialPtr material = MaterialManager::getSingleton().create(
|
|
name,
|
|
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
|
|
|
// This assigns the texture to this material. If the texture
|
|
// name is a file name, and this file exists (in a resource
|
|
// directory), it will automatically be loaded when needed. If
|
|
// not, we should already have inserted a manual loader for the texture.
|
|
if(texture)
|
|
material->getTechnique(0)->getPass(0)->createTextureUnitState(texture);
|
|
|
|
// Set bells and whistles
|
|
material->setAmbient(ambient[0], ambient[1], ambient[2]);
|
|
material->setDiffuse(diffuse[0], diffuse[1], diffuse[2], alpha);
|
|
material->setSpecular(specular[0], specular[1], specular[2], alpha);
|
|
material->setSelfIllumination(emissive[0], emissive[1], emissive[2]);
|
|
material->setShininess(glossiness);
|
|
|
|
// Enable transparancy? This is just guesswork. Perhaps we
|
|
// should use NiAlphaProperty or something instead. This looks
|
|
// like crap so it's not enabled right now.
|
|
|
|
//material->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
|
|
|
// Temporary, just to store the name of one valid material.
|
|
LASTNAME = material->getName();
|
|
}
|
|
|
|
extern "C" SceneNode *cpp_getDetachedNode()
|
|
{
|
|
SceneNode *node = root->createChildSceneNode();
|
|
root->removeChild(node);
|
|
return node;
|
|
}
|
|
|
|
extern "C" SceneNode* cpp_createNode(
|
|
char *name,
|
|
float *trafo,
|
|
SceneNode *parent,
|
|
int noRot)
|
|
{
|
|
//std::cout << "cpp_createNode(" << name << ")";
|
|
SceneNode *node = parent->createChildSceneNode(name);
|
|
//std::cout << " ... done\n";
|
|
|
|
// First is the translation vector
|
|
|
|
// TODO should be "if(!noRot)" only for exterior cells!? Yay for
|
|
// consistency. Apparently, the displacement of the base node in NIF
|
|
// files must be ignored for meshes in interior cells, but not for
|
|
// exterior cells. Or at least that's my hypothesis, and it seems
|
|
// work. There might be some other NIF trickery going on though, you
|
|
// never know when you're reverse engineering someone else's file
|
|
// format. We will handle this later.
|
|
if(!noRot)
|
|
node->setPosition(trafo[0], trafo[1], trafo[2]);
|
|
|
|
// Then a 3x3 rotation matrix.
|
|
if(!noRot)
|
|
node->setOrientation(Quaternion(Matrix3(trafo[3], trafo[4], trafo[5],
|
|
trafo[6], trafo[7], trafo[8],
|
|
trafo[9], trafo[10], trafo[11]
|
|
)));
|
|
|
|
// Scale is at the end
|
|
node->setScale(trafo[12],trafo[12],trafo[12]);
|
|
|
|
return node;
|
|
}
|
|
|
|
// Callback to make D insert a texture.
|
|
extern "C" void d_loadTexture(void* tl, Resource *r);
|
|
|
|
// Manual loader for textures
|
|
class TextureLoader : public ManualResourceLoader
|
|
{
|
|
void *textureIndex;
|
|
|
|
public:
|
|
|
|
TextureLoader(char* name, void* ti) : textureIndex(ti)
|
|
{ createTexture(name); }
|
|
~TextureLoader() {}
|
|
|
|
void createTexture(char *name)
|
|
{
|
|
// Completely disable these textures for now.
|
|
|
|
return;
|
|
// Create a manually loaded texture. Dimensions etc are dummy
|
|
// values that will be overwritten later.
|
|
TexturePtr texture = TextureManager::getSingleton().createManual
|
|
(
|
|
name, // Name
|
|
"General", // Group
|
|
TEX_TYPE_2D, // Texture type
|
|
1, 1, // Dimensions
|
|
0, // Mipmaps
|
|
//PF_DXT1, // Pixel format
|
|
PF_UNKNOWN, // Pixel format
|
|
TU_DEFAULT,
|
|
this);
|
|
|
|
// Now unload this dummy image. This forces the image to be
|
|
// reloaded when needed.
|
|
texture->unload();
|
|
}
|
|
|
|
void loadResource(Resource *resource)
|
|
{
|
|
// This makes the D code insert the image.
|
|
d_loadTexture(textureIndex, resource);
|
|
}
|
|
};
|
|
|
|
// Create a new manually loaded texture, and return the manual loader
|
|
extern "C" TextureLoader *cpp_createTexture(
|
|
char *name,
|
|
void *textureIndex)
|
|
{
|
|
return new TextureLoader(name, textureIndex);
|
|
}
|
|
|
|
int hasLoad = 0;
|
|
|
|
extern "C" void cpp_loadMemImage(
|
|
char* name, // Name to give the resource
|
|
char* type, // Image type (eg. "dds")
|
|
void* data, // Pointer to file data
|
|
unsigned int size, // Size
|
|
Texture* txt)// Texture
|
|
{
|
|
|
|
DataStreamPtr m(new MemoryDataStream(name, data, size));
|
|
Image i;
|
|
i.load(m, type);
|
|
|
|
txt->setHeight(i.getHeight());
|
|
txt->setWidth(i.getWidth());
|
|
std::cout << "New width: " << txt->getWidth()
|
|
<< " source: " << txt->getSrcWidth() << "\n";
|
|
|
|
// _loadImages requires a list of image pointers
|
|
ConstImagePtrList lst(1, &i);
|
|
txt->_loadImages(lst);
|
|
|
|
/*
|
|
if(hasLoad != 15)
|
|
{
|
|
hasLoad = 15;
|
|
|
|
std::cout << "cpp_loadMemImage: name=" << name << " type=" << type
|
|
<< " data size=" << size << "\n";
|
|
std::cout << "Data stream size=" << m->size() << "\n";
|
|
std::cout << "Image: buffer size=" << i.getSize() << " dimensions="
|
|
<< i.getWidth() << "x" << i.getHeight() << " mipmaps="
|
|
<< i.getNumMipmaps() << "\n";
|
|
std::cout << "Image format: " << i.getFormat() << "\n";
|
|
|
|
//const char* filename = "output.png";
|
|
//i.save(filename);
|
|
//std::cout << "Saved file to " << filename << "\n";
|
|
}
|
|
*/
|
|
}
|
|
|
|
/* Code currently not in use
|
|
|
|
// We need this later for animated meshes. Boy will this be a mess.
|
|
extern "C" void* cpp_setupSkeleton(char* name)
|
|
{
|
|
SkeletonPtr skel = SkeletonManager::getSingleton().create(
|
|
name, "Closet", true);
|
|
|
|
skel->load();
|
|
|
|
// Create all bones at the origin and unrotated. This is necessary
|
|
// since our submeshes each have their own model space. We must
|
|
// move the bones after creating an entity, then copy this entity.
|
|
return (void*)skel->createBone();
|
|
}
|
|
|
|
// Use this later when loading textures directly from NIF files
|
|
extern "C" void cpp_createTexture(char* name, uint width, uint height)
|
|
{
|
|
TexturePtr texture = TextureManager::getSingleton().createManual(
|
|
name, // name
|
|
"ManualTexture", // group
|
|
TEX_TYPE_2D, // type
|
|
width, hight, // width & height
|
|
0, // number of mipmaps
|
|
PF_BYTE_BGRA, // pixel format
|
|
TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for
|
|
// textures updated very often (e.g. each frame)
|
|
|
|
// Get the pixel buffer
|
|
HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer();
|
|
|
|
// Lock the pixel buffer and get a pixel box
|
|
pixelBuffer->lock(HardwareBuffer::HBL_NORMAL); // for best performance use HBL_DISCARD!
|
|
const PixelBox& pixelBox = pixelBuffer->getCurrentLock();
|
|
|
|
uint8* pDest = static_cast<uint8*>(pixelBox.data);
|
|
|
|
// Fill in some pixel data. This will give a semi-transparent blue,
|
|
// but this is of course dependent on the chosen pixel format.
|
|
for (size_t j = 0; j < 256; j++)
|
|
for(size_t i = 0; i < 256; i++)
|
|
{
|
|
*pDest++ = 255; // B
|
|
*pDest++ = 0; // G
|
|
*pDest++ = 0; // R
|
|
*pDest++ = 127; // A
|
|
}
|
|
|
|
// Unlock the pixel buffer
|
|
pixelBuffer->unlock();
|
|
|
|
// Create a material using the texture
|
|
MaterialPtr material = MaterialManager::getSingleton().create(
|
|
"DynamicTextureMaterial", // name
|
|
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
|
|
|
material->getTechnique(0)->getPass(0)->createTextureUnitState("DynamicTexture");
|
|
material->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
|
}
|
|
|
|
extern "C" void *cpp_insertBone(char* name, void* rootBone, int index)
|
|
{
|
|
return (void*) ( ((Bone*)rootBone)->createChild(index) );
|
|
}
|
|
*/
|