Added RenderTextures (And many others things)

-Added Forward, left and up vector (Vector3)
-Added Matrix4::ConcatenateAffine shortcut
-Added Quaternion::GetInverse() and Quaternion::Inverse()
-Added Resource listeners
-Added Depth and stencil pixel formats
-All enums now have an ending "max" entry
-Animation/Mesh::Add[Sequence/Skin/SubMesh] now returns a boolean
-Contexts are now resources
-Enhanced AnimatedMesh demo
-Fixed MD2 facing
-Fixed Vector3::CrossProduct
-Made Resource thread-safe
-Made OpenGL translation table global
-Many bugfixes
-MLT will now write malloc failure to the log
-Most of the strcpy were replaced with faster memcpy
-Occlusion queries availability is now always tested
-OpenGL-related includes now requires NAZARA_RENDERER_OPENGL to be
defined to have any effect
-Pixel formats now have a type
-Renamed RenderTarget::IsValid to IsRenderable
-Renamed Quaternion::GetNormalized() to GetNormal()
-Renamed Texture::Bind() to Prepare()
-Renamed VectorX::Make[Ceil|Floor] to Maximize/Minimize
-Removed MATH_MATRIX_COLUMN_MAJOR option (all matrices are column-major)
-Removed RENDERER_ACTIVATE_RENDERWINDOW_ON_CREATION option (Render
windows are active upon their creation)


Former-commit-id: 0d1da1e32c156a958221edf04a5315c75b354450
This commit is contained in:
Jérôme Leclercq 2012-09-20 22:07:30 +02:00
parent a6ed70123b
commit cd5a1b7a5e
65 changed files with 24385 additions and 22703 deletions

View File

@ -2,6 +2,8 @@ if (not _OPTIONS["one-library"]) then
project "NazaraRenderer" project "NazaraRenderer"
end end
defines "NAZARA_RENDERER_OPENGL"
files files
{ {
"../include/Nazara/Renderer/**.hpp", "../include/Nazara/Renderer/**.hpp",

View File

@ -38,9 +38,10 @@ void SetSequence(AnimatedModel& model, const NzString& name);
int main() int main()
{ {
// Tout d'abord on affiche les instructions // Tout d'abord on affiche les instructions
std::cout << "Camera controls: ZQSD" << std::endl; std::cout << "Controls: ZQSD" << std::endl;
std::cout << "Dr. Freak controls: Up, down, left and right" << std::endl;
std::cout << "Escape to quit" << std::endl; std::cout << "Escape to quit" << std::endl;
std::cout << "Left click to capture/free the mouse" << std::endl;
std::cout << "Right click to control Dr. Freak" << std::endl;
// Cette ligne active le mode de compatibilité d'OpenGL lors de l'initialisation de Nazara (Nécessaire pour le shader) // Cette ligne active le mode de compatibilité d'OpenGL lors de l'initialisation de Nazara (Nécessaire pour le shader)
NzContextParameters::defaultCompatibilityProfile = true; NzContextParameters::defaultCompatibilityProfile = true;
@ -135,8 +136,8 @@ int main()
// Le sol ne subit aucune transformation // Le sol ne subit aucune transformation
floor.matrix.MakeIdentity(); floor.matrix.MakeIdentity();
// Pour effectuer un rendu, il faut que la carte graphique sache quoi faire. // Pour effectuer un rendu, il faut que la carte graphique sache comment le faire.
// Les shaders sont de petits programmes qui donnent des instructions à la carte graphique lors du pipeline. // Les shaders sont de petits programmes qui donnent des instructions à la carte graphique lors de son pipeline.
// Ils sont aujourd'hui indispensables pour un rendu 3D, mais sont très utiles pour divers effets ! // Ils sont aujourd'hui indispensables pour un rendu 3D, mais sont très utiles pour divers effets !
// Il existe plusieurs langages de shaders, GLSL pour OpenGL, HLSL pour Direct3D et Cg qui peut être utilisé pour les deux. // Il existe plusieurs langages de shaders, GLSL pour OpenGL, HLSL pour Direct3D et Cg qui peut être utilisé pour les deux.
// Le Renderer de Nazara utilise OpenGL, par conséquent nous utiliserons le GLSL // Le Renderer de Nazara utilise OpenGL, par conséquent nous utiliserons le GLSL
@ -152,6 +153,8 @@ int main()
// Une fois le shader créé, nous devons lui spécifier les codes sources de nos shaders // Une fois le shader créé, nous devons lui spécifier les codes sources de nos shaders
// Pour notre exemple nous prendrons un shader très simple // Pour notre exemple nous prendrons un shader très simple
// Un shader doit obligatoirement posséder au moins deux codes, un pour le fragment shader et un pour le vertex shader // Un shader doit obligatoirement posséder au moins deux codes, un pour le fragment shader et un pour le vertex shader
// Le fragment shader traite la couleur de nos pixels
if (!shader.LoadFromFile(nzShaderType_Fragment, "shaders/basic.frag")) if (!shader.LoadFromFile(nzShaderType_Fragment, "shaders/basic.frag"))
{ {
std::cout << "Failed to load fragment shader from file" << std::endl; std::cout << "Failed to load fragment shader from file" << std::endl;
@ -161,7 +164,7 @@ int main()
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// Maintenant le vertex shader // Le vertex shader (Transformation des vertices de l'espace 3D vers l'espace écran)
if (!shader.LoadFromFile(nzShaderType_Vertex, "shaders/basic.vert")) if (!shader.LoadFromFile(nzShaderType_Vertex, "shaders/basic.vert"))
{ {
std::cout << "Failed to load vertex shader from file" << std::endl; std::cout << "Failed to load vertex shader from file" << std::endl;
@ -170,7 +173,7 @@ int main()
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// Une fois le code source de nos shaders chargé, nous pouvons le compiler, afin de le rendre utilisable // Une fois les codes sources de notre shader chargé, nous pouvons le compiler, afin de le rendre utilisable
if (!shader.Compile()) if (!shader.Compile())
{ {
std::cout << "Failed to compile shader" << std::endl; std::cout << "Failed to compile shader" << std::endl;
@ -182,25 +185,34 @@ int main()
// Nos ressources sont chargées, et c'est bien beau, mais il nous faudrait une fenêtre pour afficher tout ça // Nos ressources sont chargées, et c'est bien beau, mais il nous faudrait une fenêtre pour afficher tout ça
// Window représente une fenêtre singulière, pour y effectuer un rendu il nous faut une RenderWindow // Window représente une fenêtre singulière, pour y effectuer un rendu il nous faut une RenderWindow
// Tout d'abord, sa taille, disons celle du bureau divisé par deux // Tout d'abord, sa taille, disons celle du bureau divisé par deux
NzVideoMode mode = NzVideoMode::GetDesktopMode();
// Un VideoMode est une structure contenant une longueur (width), une largeur (height) et le nombre de bits par pixels (bitsPerPixel)
NzVideoMode mode = NzVideoMode::GetDesktopMode(); // Nous récupérons le mode actuellement utilisé par le bureau
// Nous divisons sa longueur et sa largeur par deux
mode.width /= 2; mode.width /= 2;
mode.height /= 2; mode.height /= 2;
NzString title = "Nazara Demo - AnimatedMesh"; // Maintenant le titre, rien de plus simple...
NzString windowTitle = "Nazara Demo - AnimatedMesh";
// Nous pouvons créer notre fenêtre ! (Via le constructeur directement ou par la méthode Create)
NzRenderWindow window; NzRenderWindow window;
// Le premier argument définit la taille de rendu de la fenêtre (Si elle possède une bordure elle sera légèrement plus grande)
// Le deuxième argument est le titre de la fenêtre lors de sa création, vous pouvez le modifier à tout moment via window.SetTitle // Le premier argument définit la taille de rendu de la fenêtre (Si elle possède une bordure elle sera légèrement plus grande).
// Le deuxième argument est le titre de la fenêtre lors de sa création, vous pouvez le modifier à tout moment via window.SetTitle.
// Le troisième argument représente la décoration de la fenêtre, sa bordure, ses boutons. // Le troisième argument représente la décoration de la fenêtre, sa bordure, ses boutons.
// Attention que cela permet à la fenêtre d'envoyer des évènements, et de changer sa taille // Attention que cela permet à la fenêtre de changer sa taille et qu'il faudra donc traiter l'évènement.
// Par défaut le troisième argument vaut nzWindowStyle_Default (Bordure + Bouton de fermeture + Redimensionnement) // Par défaut le troisième argument vaut nzWindowStyle_Default (Bordure + Bouton de fermeture + Redimensionnement)
if (!window.Create(mode, title, nzWindowStyle_Default)) if (!window.Create(mode, windowTitle, nzWindowStyle_Default))
{ {
std::cout << "Failed to create window" << std::endl; std::cout << "Failed to create window" << std::endl;
std::getchar(); std::getchar();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// Notre belle fenêtre est créée, nous pouvons la configurer
// On cache le curseur // On cache le curseur
window.SetCursor(nzWindowCursor_None); window.SetCursor(nzWindowCursor_None);
@ -215,40 +227,27 @@ int main()
unsigned int fps = 0; // Compteur de FPS unsigned int fps = 0; // Compteur de FPS
// Quelques variables pour notre improvisation de physique // Quelques variables pour notre improvisation de physique
float groundPos = drfreak.mesh.GetAABB().GetMinimum().y; // Pas très exact float groundPos = drfreak.mesh.GetAABB().GetMinimum().y; // Les coordonnées locales du "bas" du modèle
NzVector3f modelPos(0.f, groundPos, -50.f); NzVector3f modelPos(0.f, -groundPos, -50.f);
NzVector3f modelVel(0.f, 0.f, 0.f); NzVector3f modelVel(0.f, 0.f, 0.f);
NzQuaternionf modelRot(NzEulerAnglesf(0.f, 0.f, 0.f)); // Les angles d'eulers sont bien plus facile à se représenter NzQuaternionf modelOrient(NzQuaternionf::Identity());
float speed = 60.f; NzEulerAnglesf modelRot(0.f, 0.f, 0.f);
float modelSpeed = 150.f;
// Nous initialisons la matrice // Nous initialisons la matrice
drfreak.matrix = NzMatrix4f::Rotate(modelRot) * NzMatrix4f::Translate(modelPos); drfreak.matrix = NzMatrix4f::Rotate(modelOrient) * NzMatrix4f::Translate(modelPos);
// Notre caméra // Notre caméra
NzVector3f camPos(0.f, 25.f, -20.f); NzVector3f camPos(0.f, 25.f, -20.f);
NzEulerAnglesf camRot(0.f, 0.f, 0.f); NzQuaternionf camOrient(NzQuaternionf::Identity());
NzEulerAnglesf camRot(0.f, 0.f, 0.f); // Les angles d'eulers sont bien plus facile à utiliser
NzMatrix4f camMatrix = NzMatrix4f::Translate(camPos); NzMatrix4f camMatrix = NzMatrix4f::Translate(camPos);
float camSpeed = 2.f; float camSpeed = 100.f;
float sensitivity = 0.5; float sensitivity = 0.8f;
// Dernière étape, nos touches // Quelques variables
// Chaque touche fera bouger
struct Movement
{
NzVector3f direction; // La direction
NzQuaternionf rotation; // La rotation du modèle
};
std::map<NzKeyboard::Key, Movement> movements;
movements[NzKeyboard::Up] = Movement{NzVector3f(0.f, 0.f, -1.f), NzQuaternionf(NzEulerAnglesf(0.f, 180.f, 0.f))};
movements[NzKeyboard::Down] = Movement{NzVector3f(0.f, 0.f, 1.f), NzQuaternionf(NzEulerAnglesf(0.f, 0.f, 0.f))};
movements[NzKeyboard::Left] = Movement{NzVector3f(-1.f, 0.f, 0.f), NzQuaternionf(NzEulerAnglesf(0.f, 90.f, 0.f))};
movements[NzKeyboard::Right] = Movement{NzVector3f(1.f, 0.f, 0.f), NzQuaternionf(NzEulerAnglesf(0.f, -90.f, 0.f))};
NzKeyboard::Key currentKey = NzKeyboard::Undefined;
// Quelques booléens
bool camMode = true; bool camMode = true;
bool thirdPerson = false;
bool windowOpen = true; bool windowOpen = true;
// On peut commencer la boucle du programme // On peut commencer la boucle du programme
@ -258,36 +257,38 @@ int main()
NzEvent event; NzEvent event;
while (window.PollEvent(&event)) // Avons-nous un évènement dans la file ? while (window.PollEvent(&event)) // Avons-nous un évènement dans la file ?
{ {
// Nous avons un évènement // Nous avons un évènement !
switch (event.type) // De quel type est cet évènement ? switch (event.type) // De quel type est cet évènement ?
{ {
case nzEventType_Quit: // L'utilisateur/L'OS nous a demandé de terminer notre exécution case nzEventType_Quit: // L'utilisateur/L'OS nous a demandé de terminer notre exécution
windowOpen = false; // Nous terminons alors la boucle windowOpen = false; // Nous terminons alors la boucle
break; break;
case nzEventType_MouseMoved: case nzEventType_MouseMoved: // La souris a bougé
{ {
// Si nous ne sommes pas en mode caméra, on ne traite pas l'évènement // Si nous ne sommes pas en mode free-fly, on ne traite pas l'évènement
if (!camMode) if (!camMode || thirdPerson)
break; break;
// On modifie l'angle de la caméra grâce au déplacement relatif de la souris // On modifie l'angle de la caméra grâce au déplacement relatif de la souris
camRot.yaw = NzNormalizeAngle(camRot.yaw - event.mouseMove.deltaX*sensitivity); camRot.yaw = NzNormalizeAngle(camRot.yaw - event.mouseMove.deltaX*sensitivity);
// Pour éviter les loopings, on restreint les angles // Pour éviter les loopings mais surtout les problèmes de calculation de la matrice de vue, on restreint les angles
camRot.pitch = NzClamp(camRot.pitch + event.mouseMove.deltaY*sensitivity, -90.f, 90.f); camRot.pitch = NzClamp(camRot.pitch - event.mouseMove.deltaY*sensitivity, -89.f, 89.f);
// La matrice vue représente les transformations effectuées par la caméra // La matrice vue représente les transformations effectuées par la caméra
// On recalcule la matrice de la caméra et on l'envoie au renderer // On recalcule la matrice de la caméra et on l'envoie au renderer
NzRenderer::SetMatrix(nzMatrixType_View, NzMatrix4f::Translate(camPos) * NzMatrix4f::Rotate(camRot)); camOrient = camRot; // Conversion des angles d'euler en quaternion
NzRenderer::SetMatrix(nzMatrixType_View, NzMatrix4f::LookAt(camPos, camPos + camOrient * NzVector3f::Forward()));
// Pour éviter que le curseur ne sorte de l'écran, nous le renvoyons au centre de la fenêtre // Pour éviter que le curseur ne sorte de l'écran, nous le renvoyons au centre de la fenêtre
NzMouse::SetPosition(window.GetWidth()/2, window.GetHeight()/2, window); NzMouse::SetPosition(window.GetWidth()/2, window.GetHeight()/2, window);
break; break;
} }
case nzEventType_MouseButtonPressed: case nzEventType_MouseButtonPressed: // L'utilisateur (ou son chat) vient de cliquer sur la souris
if (event.mouseButton.button == NzMouse::Left) if (event.mouseButton.button == NzMouse::Left) // Est-ce le clic gauche ?
{ {
// L'utilisateur vient d'appuyer sur le bouton left de la souris // L'utilisateur vient d'appuyer sur le bouton left de la souris
// Nous allons inverser le mode caméra et montrer/cacher le curseur en conséquence // Nous allons inverser le mode caméra et montrer/cacher le curseur en conséquence
@ -301,44 +302,54 @@ int main()
camMode = true; camMode = true;
window.SetCursor(nzWindowCursor_None); window.SetCursor(nzWindowCursor_None);
} }
}
else if (event.mouseButton.button == NzMouse::Right) // Est-ce le clic droit ?
{
if (thirdPerson)
{
// On arrête le mouvement
SetSequence(drfreak, "stand");
// Afin de synchroniser le quaternion avec les angles d'euler
camRot = camOrient.ToEulerAngles();
thirdPerson = false;
}
else
thirdPerson = true;
} }
break; break;
case nzEventType_Resized: // L'utilisateur a changé notre taille, le coquin ! case nzEventType_Resized: // L'utilisateur a changé la taille de la fenêtre, le coquin !
NzRenderer::SetViewport(NzRectui(0, 0, event.size.width, event.size.height)); // Adaptons l'affichage NzRenderer::SetViewport(NzRectui(0, 0, event.size.width, event.size.height)); // Adaptons l'affichage
// Il nous faut aussi mettre à jour notre matrice de projection // Il nous faut aussi mettre à jour notre matrice de projection
NzRenderer::SetMatrix(nzMatrixType_Projection, NzMatrix4f::Perspective(NzDegrees(70.f), static_cast<float>(event.size.width)/event.size.height, 1.f, 1000.f)); NzRenderer::SetMatrix(nzMatrixType_Projection, NzMatrix4f::Perspective(NzDegrees(70.f), static_cast<float>(event.size.width)/event.size.height, 1.f, 1000.f));
break; break;
case nzEventType_KeyPressed: case nzEventType_KeyPressed: // Une touche du clavier vient d'être enfoncée
if (!event.key.repeated) // Si la touche n'est pas répétée if (thirdPerson &&
(event.key.code == NzKeyboard::Z || // Est-ce la touche Z ?
event.key.code == NzKeyboard::S || // Ou bien la touche S ?
event.key.code == NzKeyboard::Q || // Ou encore la touche Q ?
event.key.code == NzKeyboard::D)) // Et pourquoi pas la touche D ?
{ {
auto it = movements.find(event.key.code); // Si une touche concernant le déplacement est appuyée
if (it != movements.end())
{
// Si la touche est une touche de mouvement
SetSequence(drfreak, "run"); // On anime le personnage pour qu'il ait une animation de déplacement SetSequence(drfreak, "run"); // On anime le personnage pour qu'il ait une animation de déplacement
modelRot = it->second.rotation; // On change la rotation du modèle
drfreak.matrix = NzMatrix4f::Rotate(modelRot) * NzMatrix4f::Translate(modelPos); // On recalcule sa matrice
modelVel = it->second.direction * speed; // On change la vitesse de déplacement
currentKey = event.key.code;
} }
} else if (event.key.code == NzKeyboard::Escape)
if (event.key.code == NzKeyboard::Escape)
windowOpen = false; windowOpen = false;
break; break;
case nzEventType_KeyReleased: case nzEventType_KeyReleased: // Une touche du clavier vient d'être relachée
if (event.key.code == currentKey) if (thirdPerson &&
!NzKeyboard::IsKeyPressed(NzKeyboard::Z) && // Est-ce que la touche Z est enfoncée en ce moment ?
!NzKeyboard::IsKeyPressed(NzKeyboard::S) && // Ou bien la touche S ?
!NzKeyboard::IsKeyPressed(NzKeyboard::Q) && // Etc..
!NzKeyboard::IsKeyPressed(NzKeyboard::D)) // Etc..
{ {
// Si plus aucune touche de déplacement n'est enfoncée
SetSequence(drfreak, "stand"); SetSequence(drfreak, "stand");
modelVel = NzVector3f(0.f); // On arrête le déplacement
break;
} }
break; break;
@ -348,81 +359,115 @@ int main()
} }
} }
// On active le shader et paramètrons le rendu // Mise à jour de la partie logique
NzRenderer::SetShader(&shader);
NzRenderer::Enable(nzRendererParameter_DepthTest, true);
NzRenderer::SetClearColor(128, 128, 128);
NzRenderer::Clear(nzRendererClear_Color | nzRendererClear_Depth);
if (updateClock.GetMilliseconds() >= 1000/60) // 60 fois par seconde if (updateClock.GetMilliseconds() >= 1000/60) // 60 fois par seconde
{ {
float elapsedTime = updateClock.GetSeconds(); // Le temps depuis la dernière mise à jour float elapsedTime = updateClock.GetSeconds(); // Le temps depuis la dernière mise à jour
// Déplacement de la caméra // Déplacement de la caméra
static const NzVector3f forward(NzVector3f::UnitZ()); static const NzVector3f forward(NzVector3f::Forward());
static const NzVector3f left(NzVector3f::UnitX()); static const NzVector3f left(NzVector3f::Left());
static const NzVector3f up(NzVector3f::UnitY()); static const NzVector3f up(NzVector3f::Up());
// Notre rotation sous forme de quaternion nous permet de tourner un vecteur // Notre rotation sous forme de quaternion nous permet de tourner un vecteur
NzQuaternionf quaternion(camRot);
// Par exemple ici, quaternion * forward nous permet de récupérer le vecteur de la direction "avant" // Par exemple ici, quaternion * forward nous permet de récupérer le vecteur de la direction "avant"
if (thirdPerson)
{
// Nous déplaçons le personnage en fonction des touches pressées
if (NzKeyboard::IsKeyPressed(NzKeyboard::Z)) if (NzKeyboard::IsKeyPressed(NzKeyboard::Z))
camPos += quaternion * forward * camSpeed; modelPos += modelOrient * forward * modelSpeed * elapsedTime;
if (NzKeyboard::IsKeyPressed(NzKeyboard::S)) if (NzKeyboard::IsKeyPressed(NzKeyboard::S))
camPos -= quaternion * forward * camSpeed; modelPos -= modelOrient * forward * modelSpeed * elapsedTime;
if (NzKeyboard::IsKeyPressed(NzKeyboard::Q)) if (NzKeyboard::IsKeyPressed(NzKeyboard::Q))
camPos += quaternion * left * camSpeed; modelRot.yaw += camSpeed * elapsedTime;
if (NzKeyboard::IsKeyPressed(NzKeyboard::D)) if (NzKeyboard::IsKeyPressed(NzKeyboard::D))
camPos -= quaternion * left * camSpeed; modelRot.yaw -= camSpeed * elapsedTime;
modelOrient = modelRot;
}
else
{
// Sinon, c'est la caméra qui se déplace (en fonction des mêmes touches)
// Un boost en maintenant le shift gauche
float speed = (NzKeyboard::IsKeyPressed(NzKeyboard::Key::LShift)) ? camSpeed*5 : camSpeed;
if (NzKeyboard::IsKeyPressed(NzKeyboard::Z))
camPos += camOrient * forward * speed * elapsedTime;
if (NzKeyboard::IsKeyPressed(NzKeyboard::S))
camPos -= camOrient * forward * speed * elapsedTime;
if (NzKeyboard::IsKeyPressed(NzKeyboard::Q))
camPos += camOrient * left * speed * elapsedTime;
if (NzKeyboard::IsKeyPressed(NzKeyboard::D))
camPos -= camOrient * left * speed * elapsedTime;
// En revanche, ici la hauteur est toujours la même, peu importe notre orientation // En revanche, ici la hauteur est toujours la même, peu importe notre orientation
if (NzKeyboard::IsKeyPressed(NzKeyboard::Space)) if (NzKeyboard::IsKeyPressed(NzKeyboard::Space))
camPos += up * camSpeed; camPos += up * speed * elapsedTime;
if (NzKeyboard::IsKeyPressed(NzKeyboard::LControl)) if (NzKeyboard::IsKeyPressed(NzKeyboard::LControl))
camPos -= up * camSpeed; camPos -= up * speed * elapsedTime;
}
// Oui le quaternion et la matrice sont calculés même si la caméra ne bouge pas // Oui les quaternions et les matrices sont calculés même si la caméra ne bouge pas
// C'est une limitation de mon implémentation, qui ne sera pas présente une fois les NzSceneNode intégrés // C'est une limitation de mon implémentation, qui ne sera pas présente une fois les NzSceneNode intégrés
NzRenderer::SetMatrix(nzMatrixType_View, NzMatrix4f::Translate(camPos) * NzMatrix4f::Rotate(camRot)); if (thirdPerson)
{
static NzQuaternionf rotDown(NzEulerAnglesf(-15.f, 0.f, 0.f)); // Une rotation pour regarder vers le bas
camOrient = modelOrient * rotDown;
camPos = modelPos + camOrient * NzVector3f(0.f, 25.f, 60.f);
}
NzRenderer::SetMatrix(nzMatrixType_View, NzMatrix4f::LookAt(camPos, camPos + camOrient * NzVector3f::Forward()));
// Mise à jour de la matrice du personnage
drfreak.matrix = NzMatrix4f::Rotate(modelOrient) * NzMatrix4f::Translate(modelPos);
// Animation // Animation
AnimateModel(drfreak, elapsedTime); AnimateModel(drfreak, elapsedTime);
updateClock.Restart(); updateClock.Restart();
// "Physique"
if (modelVel != NzVector3f::Zero())
{
modelPos += modelVel * elapsedTime;
// Mise à jour de la matrice
drfreak.matrix = NzMatrix4f::Rotate(modelRot) * NzMatrix4f::Translate(modelPos);
}
} }
// On active le shader et paramètrons le rendu
NzRenderer::SetShader(&shader);
// Notre scène 3D requiert un test de profondeur
NzRenderer::Enable(nzRendererParameter_DepthTest, true);
// Nous voulons avoir un fond bien gris
NzRenderer::SetClearColor(128, 128, 128);
// Et nous effaçons les buffers de couleur et de profondeur
NzRenderer::Clear(nzRendererClear_Color | nzRendererClear_Depth);
// Affichage des meshs // Affichage des meshs
DrawModel(floor); DrawModel(floor);
// Notre Dr. Freak possède des normales, nous pouvons alors culler les faces qu'on ne voit pas // Notre Dr. Freak possède des normales, nous pouvons alors éliminer les faces qu'on ne voit pas
NzRenderer::Enable(nzRendererParameter_FaceCulling, true); NzRenderer::Enable(nzRendererParameter_FaceCulling, true);
DrawModel(drfreak); DrawModel(drfreak);
NzRenderer::Enable(nzRendererParameter_FaceCulling, false); NzRenderer::Enable(nzRendererParameter_FaceCulling, false);
window.Display(); // Nous mettons à jour l'écran // Nous mettons à jour l'écran
window.Display();
fps++; fps++;
// Toutes les secondes // Toutes les secondes
if (secondClock.GetMilliseconds() >= 1000) if (secondClock.GetMilliseconds() >= 1000)
{ {
window.SetTitle(title + " (FPS: " + NzString::Number(fps) + ')'); window.SetTitle(windowTitle + " (FPS: " + NzString::Number(fps) + ')');
fps = 0; fps = 0;
secondClock.Restart(); secondClock.Restart();
} }
@ -567,10 +612,10 @@ bool CreateFloorMesh(NzMesh* mesh)
mesh->AddSubMesh(subMesh); mesh->AddSubMesh(subMesh);
// Nos ressources sont notifiées utilisées par le mesh et le submesh, nous pouvons les rendre éphèmères. // Nos ressources sont notifiées utilisées par le mesh et le submesh, nous pouvons les rendre éphèmères.
// Les ressources seront donc automatiquement libérées lorsque plus aucune classe n'en aura besoin // Les ressources seront donc automatiquement libérées lorsqu'elles ne seront plus référencées par une classe
buffer->SetPersistent(false); buffer->SetPersistent(false);
declaration->SetPersistent(false); declaration->SetPersistent(false);
subMesh->SetPersistent(false); // Pour le submesh, c'est déjà à false à la base subMesh->SetPersistent(false); // Pour le submesh, c'est déjà le comportement par défaut
return true; return true;
} }
@ -606,8 +651,12 @@ void SetSequence(AnimatedModel& model, const NzString& sequenceName)
const NzAnimation* animation = model.mesh.GetAnimation(); const NzAnimation* animation = model.mesh.GetAnimation();
// Nous nous basons sur l'assertion que la séquence existe (Chose que nous pouvons tester avec HasSequence()) // Nous nous basons sur l'assertion que la séquence existe (Chose que nous pouvons tester avec HasSequence())
model.currentSequence = animation->GetSequence(sequenceName); const NzSequence* sequence = animation->GetSequence(sequenceName);
if (model.currentSequence != sequence)
{
model.currentSequence = sequence;
// Pour avoir une interpolation entre la séquence précédente et celle-ci, nous n'affectons que nextFrame // Pour avoir une interpolation entre la séquence précédente et celle-ci, nous n'affectons que nextFrame
model.nextFrame = model.currentSequence->firstFrame; model.nextFrame = model.currentSequence->firstFrame;
} }
}

View File

@ -52,6 +52,7 @@
#include <Nazara/Core/Mutex.hpp> #include <Nazara/Core/Mutex.hpp>
#include <Nazara/Core/NonCopyable.hpp> #include <Nazara/Core/NonCopyable.hpp>
#include <Nazara/Core/Resource.hpp> #include <Nazara/Core/Resource.hpp>
#include <Nazara/Core/ResourceListener.hpp>
#include <Nazara/Core/ResourceLoader.hpp> #include <Nazara/Core/ResourceLoader.hpp>
#include <Nazara/Core/Semaphore.hpp> #include <Nazara/Core/Semaphore.hpp>
#include <Nazara/Core/String.hpp> #include <Nazara/Core/String.hpp>

View File

@ -67,6 +67,7 @@
#define NAZARA_THREADSAFETY_FILE 1 // NzFile #define NAZARA_THREADSAFETY_FILE 1 // NzFile
#define NAZARA_THREADSAFETY_HASHDIGEST 0 // NzHashDigest #define NAZARA_THREADSAFETY_HASHDIGEST 0 // NzHashDigest
#define NAZARA_THREADSAFETY_LOG 1 // NzLog #define NAZARA_THREADSAFETY_LOG 1 // NzLog
#define NAZARA_THREADSAFETY_RESOURCE 1 // NzResource
#define NAZARA_THREADSAFETY_STRING 1 // NzString (COW) #define NAZARA_THREADSAFETY_STRING 1 // NzString (COW)
#define NAZARA_THREADSAFETY_STRINGSTREAM 0 // NzStringStream #define NAZARA_THREADSAFETY_STRINGSTREAM 0 // NzStringStream

View File

@ -12,7 +12,9 @@ enum nzEndianness
nzEndianness_Unknown = -1, nzEndianness_Unknown = -1,
nzEndianness_BigEndian, nzEndianness_BigEndian,
nzEndianness_LittleEndian nzEndianness_LittleEndian,
nzEndianness_Max = nzEndianness_LittleEndian
}; };
enum nzErrorType enum nzErrorType
@ -20,7 +22,9 @@ enum nzErrorType
nzErrorType_AssertFailed, nzErrorType_AssertFailed,
nzErrorType_Internal, nzErrorType_Internal,
nzErrorType_Normal, nzErrorType_Normal,
nzErrorType_Warning nzErrorType_Warning,
nzErrorType_Max = nzErrorType_Warning
}; };
#endif // NAZARA_ENUMS_CORE_HPP #endif // NAZARA_ENUMS_CORE_HPP

View File

@ -8,6 +8,32 @@
#define NAZARA_RESOURCE_HPP #define NAZARA_RESOURCE_HPP
#include <Nazara/Prerequesites.hpp> #include <Nazara/Prerequesites.hpp>
#include <set>
#if NAZARA_CORE_THREADSAFE && NAZARA_THREADSAFETY_RESOURCE
#include <Nazara/Core/ThreadSafety.hpp>
#else
#include <Nazara/Core/ThreadSafetyOff.hpp>
#endif
class NzResourceListener;
struct NzResourceEntry
{
NzResourceEntry(NzResourceListener* resourceListener, int i = 0) :
listener(resourceListener),
index(i)
{
}
bool operator<(const NzResourceEntry& rhs) const
{
return listener < rhs.listener;
}
NzResourceListener* listener;
int index;
};
class NAZARA_API NzResource class NAZARA_API NzResource
{ {
@ -16,14 +42,30 @@ class NAZARA_API NzResource
NzResource(const NzResource& resource); NzResource(const NzResource& resource);
virtual ~NzResource(); virtual ~NzResource();
void AddResourceListener(NzResourceListener* listener, int index = 0) const;
void AddResourceReference() const; void AddResourceReference() const;
bool IsPersistent() const; bool IsPersistent() const;
void RemoveResourceListener(NzResourceListener* listener) const;
void RemoveResourceReference() const; void RemoveResourceReference() const;
void SetPersistent(bool persistent = true); void SetPersistent(bool persistent = true);
protected:
void NotifyCreated();
void NotifyDestroy();
private: private:
void EnsureResourceListenerUpdate() const;
NazaraMutexAttrib(m_mutex, mutable)
// Je fais précéder le nom par 'resource' pour éviter les éventuels conflits de noms // Je fais précéder le nom par 'resource' pour éviter les éventuels conflits de noms
mutable bool m_resourcePersistent; mutable std::set<NzResourceEntry> m_resourceListeners;
mutable std::set<NzResourceEntry> m_resourceListenersCache;
mutable bool m_resourceListenerUpdated;
bool m_resourcePersistent;
mutable unsigned int m_resourceReferenceCount; mutable unsigned int m_resourceReferenceCount;
}; };

View File

@ -0,0 +1,25 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_RESOURCELISTENER_HPP
#define NAZARA_RESOURCELISTENER_HPP
#include <Nazara/Prerequesites.hpp>
class NzResource;
class NAZARA_API NzResourceListener
{
public:
NzResourceListener() = default;
virtual ~NzResourceListener();
virtual void OnResourceCreated(const NzResource* resource, int index);
virtual void OnResourceDestroy(const NzResource* resource, int index);
virtual void OnResourceReleased(const NzResource* resource, int index);
};
#endif // NAZARA_RESOURCELISTENER_HPP

View File

@ -15,7 +15,7 @@ bool NzResourceLoader<Type, Parameters>::LoadFromFile(Type* resource, const NzSt
#if NAZARA_CORE_SAFE #if NAZARA_CORE_SAFE
if (!parameters.IsValid()) if (!parameters.IsValid())
{ {
NazaraError("Invalid Parameters"); NazaraError("Invalid parameters");
return false; return false;
} }
#endif #endif
@ -81,7 +81,7 @@ bool NzResourceLoader<Type, Parameters>::LoadFromStream(Type* resource, NzInputS
#if NAZARA_CORE_SAFE #if NAZARA_CORE_SAFE
if (!parameters.IsValid()) if (!parameters.IsValid())
{ {
NazaraError("Invalid Parameters"); NazaraError("Invalid parameters");
return false; return false;
} }
@ -117,7 +117,7 @@ bool NzResourceLoader<Type, Parameters>::LoadFromStream(Type* resource, NzInputS
template<typename Type, typename Parameters> template<typename Type, typename Parameters>
void NzResourceLoader<Type, Parameters>::RegisterLoader(const NzString& fileExtensions, CheckFunction checkFunc, LoadFunction loadFunc) void NzResourceLoader<Type, Parameters>::RegisterLoader(const NzString& fileExtensions, CheckFunction checkFunc, LoadFunction loadFunc)
{ {
/// Trouver une alternative à ce code monstrueux ///FIXME: Trouver une alternative à ce code monstrueux
std::vector<NzString> exts; std::vector<NzString> exts;
fileExtensions.SplitAny(exts, " /\\.,;|-_"); fileExtensions.SplitAny(exts, " /\\.,;|-_");

View File

@ -301,7 +301,7 @@ class NAZARA_API NzString : public NzHashable
}; };
static SharedString emptyString; static SharedString emptyString;
static unsigned int npos; static const unsigned int npos;
private: private:
void EnsureOwnership(); void EnsureOwnership();

View File

@ -33,9 +33,6 @@
// Définit le radian comme l'unité utilisée pour les angles // Définit le radian comme l'unité utilisée pour les angles
#define NAZARA_MATH_ANGLE_RADIAN 0 #define NAZARA_MATH_ANGLE_RADIAN 0
// Définit la disposition des matrices en colonnes (Façon OpenGL)
#define NAZARA_MATH_MATRIX_COLUMN_MAJOR 1
// Optimise les opérations entre matrices affines (Demande plusieurs comparaisons pour déterminer si une matrice est affine) // Optimise les opérations entre matrices affines (Demande plusieurs comparaisons pour déterminer si une matrice est affine)
#define NAZARA_MATH_MATRIX4_CHECK_AFFINE 0 #define NAZARA_MATH_MATRIX4_CHECK_AFFINE 0

View File

@ -38,6 +38,7 @@ template<typename T> class NzMatrix4
~NzMatrix4(); ~NzMatrix4();
NzMatrix4 Concatenate(const NzMatrix4& matrix) const; NzMatrix4 Concatenate(const NzMatrix4& matrix) const;
NzMatrix4 ConcatenateAffine(const NzMatrix4& matrix) const;
T GetDeterminant() const; T GetDeterminant() const;
NzMatrix4 GetInverse() const; NzMatrix4 GetInverse() const;
@ -54,7 +55,7 @@ template<typename T> class NzMatrix4
bool IsDefined() const; bool IsDefined() const;
void MakeIdentity(); void MakeIdentity();
void MakeLookAt(const NzVector3<T>& eye, const NzVector3<T>& center, const NzVector3<T>& up); void MakeLookAt(const NzVector3<T>& eye, const NzVector3<T>& target, const NzVector3<T>& up = NzVector3<T>::Up());
void MakeOrtho(T left, T top, T width, T height, T zNear = -1.0, T zFar = 1.0); void MakeOrtho(T left, T top, T width, T height, T zNear = -1.0, T zFar = 1.0);
void MakePerspective(T angle, T ratio, T zNear, T zFar); void MakePerspective(T angle, T ratio, T zNear, T zFar);
void MakeRotation(const NzQuaternion<T>& rotation); void MakeRotation(const NzQuaternion<T>& rotation);
@ -106,7 +107,7 @@ template<typename T> class NzMatrix4
static NzMatrix4 Concatenate(const NzMatrix4& m1, const NzMatrix4& m2); static NzMatrix4 Concatenate(const NzMatrix4& m1, const NzMatrix4& m2);
static NzMatrix4 ConcatenateAffine(const NzMatrix4& m1, const NzMatrix4& m2); static NzMatrix4 ConcatenateAffine(const NzMatrix4& m1, const NzMatrix4& m2);
static NzMatrix4 Identity(); static NzMatrix4 Identity();
static NzMatrix4 LookAt(const NzVector3<T>& eye, const NzVector3<T>& center, const NzVector3<T>& up); static NzMatrix4 LookAt(const NzVector3<T>& eye, const NzVector3<T>& target, const NzVector3<T>& up = NzVector3<T>::Up());
static NzMatrix4 Ortho(T left, T top, T width, T height, T zNear = -1.0, T zFar = 1.0); static NzMatrix4 Ortho(T left, T top, T width, T height, T zNear = -1.0, T zFar = 1.0);
static NzMatrix4 Perspective(T angle, T ratio, T zNear, T zFar); static NzMatrix4 Perspective(T angle, T ratio, T zNear, T zFar);
static NzMatrix4 Rotate(const NzQuaternion<T>& rotation); static NzMatrix4 Rotate(const NzQuaternion<T>& rotation);

View File

@ -74,6 +74,12 @@ NzMatrix4<T> NzMatrix4<T>::Concatenate(const NzMatrix4& matrix) const
return Concatenate(*this, matrix); return Concatenate(*this, matrix);
} }
template<typename T>
NzMatrix4<T> NzMatrix4<T>::ConcatenateAffine(const NzMatrix4& matrix) const
{
return ConcatenateAffine(*this, matrix);
}
template<typename T> template<typename T>
T NzMatrix4<T>::GetDeterminant() const T NzMatrix4<T>::GetDeterminant() const
{ {
@ -162,11 +168,7 @@ NzVector3<T> NzMatrix4<T>::GetTranslation() const
} }
#endif #endif
#if NAZARA_MATH_MATRIX_COLUMN_MAJOR
return NzVector3<T>(m_sharedMatrix->m41, m_sharedMatrix->m42, m_sharedMatrix->m43); return NzVector3<T>(m_sharedMatrix->m41, m_sharedMatrix->m42, m_sharedMatrix->m43);
#else
return NzVector3<T>(m_sharedMatrix->m14, m_sharedMatrix->m24, m_sharedMatrix->m34);
#endif
} }
template<typename T> template<typename T>
@ -229,17 +231,10 @@ bool NzMatrix4<T>::IsAffine() const
} }
#endif #endif
#if NAZARA_MATH_MATRIX_COLUMN_MAJOR
return NzNumberEquals(m_sharedMatrix->m14, F(0.0)) && return NzNumberEquals(m_sharedMatrix->m14, F(0.0)) &&
NzNumberEquals(m_sharedMatrix->m24, F(0.0)) && NzNumberEquals(m_sharedMatrix->m24, F(0.0)) &&
NzNumberEquals(m_sharedMatrix->m34, F(0.0)) && NzNumberEquals(m_sharedMatrix->m34, F(0.0)) &&
NzNumberEquals(m_sharedMatrix->m44, F(1.0)); NzNumberEquals(m_sharedMatrix->m44, F(1.0));
#else
return NzNumberEquals(m_sharedMatrix->m41, F(0.0)) &&
NzNumberEquals(m_sharedMatrix->m42, F(0.0)) &&
NzNumberEquals(m_sharedMatrix->m43, F(0.0)) &&
NzNumberEquals(m_sharedMatrix->m44, F(1.0));
#endif
} }
template<typename T> template<typename T>
@ -260,86 +255,80 @@ void NzMatrix4<T>::MakeIdentity()
template<typename T> template<typename T>
void NzMatrix4<T>::MakeOrtho(T left, T top, T width, T height, T zNear, T zFar) void NzMatrix4<T>::MakeOrtho(T left, T top, T width, T height, T zNear, T zFar)
{ {
#if NAZARA_MATH_MATRIX_COLUMN_MAJOR // http://msdn.microsoft.com/en-us/library/windows/desktop/bb204941(v=vs.85).aspx
Set(F(2.0)/(width-left), F(0.0), F(0.0), -(width+left)/(width-left), Set(F(2.0)/(width-left), F(0.0), F(0.0), -(width+left)/(width-left),
F(0.0), F(2.0)/(top-height), F(0.0), -(top+height)/(top-height), F(0.0), F(2.0)/(top-height), F(0.0), -(top+height)/(top-height),
F(0.0), F(0.0), F(-2.0)/(zFar-zNear), -(zFar+zNear)/(zFar-zNear), F(0.0), F(0.0), F(-2.0)/(zFar-zNear), -(zFar+zNear)/(zFar-zNear),
F(0.0), F(0.0), F(0.0), F(1.0)); F(0.0), F(0.0), F(0.0), F(1.0));
#else
Set(F(2.0)/(width-left), F(0.0), F(0.0), F(0.0),
F(0.0), F(2.0)/(top-height), F(0.0), F(0.0),
F(0.0), F(0.0), F(-2.0)/(zFar-zNear), F(0.0),
-(width+left)/(width-left), -(top+height)/(top-height), -(zFar+zNear)/(zFar-zNear), F(1.0));
#endif
} }
template<typename T> template<typename T>
void NzMatrix4<T>::MakeLookAt(const NzVector3<T>& eye, const NzVector3<T>& center, const NzVector3<T>& up) void NzMatrix4<T>::MakeLookAt(const NzVector3<T>& eye, const NzVector3<T>& target, const NzVector3<T>& up)
{ {
// http://www.opengl.org/sdk/docs/man/xhtml/gluLookAt.xml NzVector3<T> f = NzVector3<T>::Normalize(target - eye);
NzVector3<T> f = center - eye; NzVector3<T> u(up.GetNormal());
f.Normalize(); NzVector3<T> s = NzVector3<T>::Normalize(f.CrossProduct(u));
NzVector3<T> u = up;
u.Normalize();
NzVector3<T> s = f.CrossProduct(u);
u = s.CrossProduct(f); u = s.CrossProduct(f);
#if NAZARA_MATH_MATRIX_COLUMN_MAJOR Set(s.x, u.x, -f.x, T(0.0),
Set(s.x, s.y, s.z, F(0.0), s.y, u.y, -f.y, T(0.0),
u.x, u.y, u.z, F(0.0), s.z, u.z, -f.z, T(0.0),
-f.x, -f.y, -f.z, F(0.0), -s.DotProduct(eye), -u.DotProduct(eye), f.DotProduct(eye), T(1.0));
F(0.0), F(0.0), F(0.0), F(1.0));
#else
Set(s.x, u.x, -f.x, F(0.0),
s.y, u.y, -f.y, F(0.0),
s.z, u.z, -f.z, F(0.0),
F(0.0), F(0.0), F(0.0), F(1.0));
#endif
Concatenate(Translate(-eye));
} }
template<typename T> template<typename T>
void NzMatrix4<T>::MakePerspective(T angle, T ratio, T zNear, T zFar) void NzMatrix4<T>::MakePerspective(T angle, T ratio, T zNear, T zFar)
{ {
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb204944(v=vs.85).aspx
#if NAZARA_MATH_ANGLE_RADIAN #if NAZARA_MATH_ANGLE_RADIAN
angle /= F(2.0); angle /= F(2.0);
#else #else
angle = NzDegreeToRadian(angle/2); angle = NzDegreeToRadian(angle/F(2.0));
#endif #endif
T f = F(1.0) / std::tan(angle); T yScale = F(1.0) / std::tan(angle);
#if NAZARA_MATH_MATRIX_COLUMN_MAJOR Set(yScale / ratio, F(0.0), F(0.0), F(0.0),
Set(f / ratio, F(0.0), F(0.0), F(0.0), F(0.0), yScale, F(0.0), F(0.0),
F(0.0), f, F(0.0), F(0.0), F(0.0), F(0.0), zFar / (zNear-zFar), F(-1.0),
F(0.0), F(0.0), (zNear+zFar) / (zNear-zFar), F(-1.0), F(0.0), F(0.0), (zNear*zFar) / (zNear-zFar), F(0.0));
F(0.0), F(0.0), (F(2.0)*zNear*zFar) / (zNear-zFar), F(1.0));
#else
Set(f / ratio, F(0.0), F(0.0), F(0.0),
F(0.0), f, F(0.0), F(0.0),
F(0.0), F(0.0), (zNear+zFar) / (zNear-zFar), (F(2.0)*zNear*zFar) / (zNear-zFar),
F(0.0), F(0.0), F(-1.0), F(1.0));
#endif
} }
template<typename T> template<typename T>
void NzMatrix4<T>::MakeRotation(const NzQuaternion<T>& rotation) void NzMatrix4<T>::MakeRotation(const NzQuaternion<T>& rotation)
{ {
// http://stackoverflow.com/questions/1556260/convert-quaternion-rotation-to-rotation-matrix // http://www.flipcode.com/documents/matrfaq.html#Q54
#if NAZARA_MATH_MATRIX_COLUMN_MAJOR /*
Set(F(1.0) - F(2.0)*rotation.y*rotation.y - F(2.0)*rotation.z*rotation.z, F(2.0)*rotation.x*rotation.y - F(2.0)*rotation.z*rotation.w, F(2.0)*rotation.x*rotation.z + F(2.0)*rotation.y*rotation.w, F(0.0), | 2 2 |
F(2.0)*rotation.x*rotation.y + F(2.0)*rotation.z*rotation.w, F(1.0) - F(2.0)*rotation.x*rotation.x - F(2.0)*rotation.z*rotation.z, F(2.0)*rotation.y*rotation.z - F(2.0)*rotation.x*rotation.w, F(0.0), | 1 - 2Y - 2Z 2XY + 2ZW 2XZ - 2YW |
F(2.0)*rotation.x*rotation.z - F(2.0)*rotation.y*rotation.w, F(2.0)*rotation.y*rotation.z + F(2.0)*rotation.x*rotation.w, F(1.0) - F(2.0)*rotation.x*rotation.x - F(2.0)*rotation.y*rotation.y, F(0.0), | |
F(0.0), F(0.0), F(0.0), F(1.0)); | 2 2 |
#else M = | 2XY - 2ZW 1 - 2X - 2Z 2YZ + 2XW |
Set(F(1.0) - F(2.0)*rotation.y*rotation.y - F(2.0)*rotation.z*rotation.z, F(2.0)*rotation.x*rotation.y + F(2.0)*rotation.z*rotation.w, F(2.0)*rotation.x*rotation.z - F(2.0)*rotation.y*rotation.w, F(0.0), | |
F(2.0)*rotation.x*rotation.y - F(2.0)*rotation.z*rotation.w, F(1.0) - F(2.0)*rotation.x*rotation.x - F(2.0)*rotation.z*rotation.z, F(2.0)*rotation.y*rotation.z + F(2.0)*rotation.x*rotation.w, F(0.0), | 2 2 |
F(2.0)*rotation.x*rotation.z + F(2.0)*rotation.y*rotation.w, F(2.0)*rotation.y*rotation.z - F(2.0)*rotation.x*rotation.w, F(1.0) - F(2.0)*rotation.x*rotation.x - F(2.0)*rotation.y*rotation.y, F(0.0), | 2XZ + 2YW 2YZ - 2XW 1 - 2X - 2Y |
F(0.0), F(0.0), F(0.0), F(1.0)); | |
#endif */
///FIXME: À corriger (Rotation quaternino != rotation matricielle)
Set(F(1.0) - F(2.0)*rotation.y*rotation.y - F(2.0)*rotation.z*rotation.z,
F(2.0)*rotation.x*rotation.y + F(2.0)*rotation.z*rotation.w,
F(2.0)*rotation.x*rotation.z - F(2.0)*rotation.y*rotation.w,
F(0.0),
F(2.0)*rotation.x*rotation.y - F(2.0)*rotation.z*rotation.w,
F(1.0) - F(2.0)*rotation.x*rotation.x - F(2.0)*rotation.z*rotation.z,
F(2.0)*rotation.y*rotation.z + F(2.0)*rotation.x*rotation.w,
F(0.0),
F(2.0)*rotation.x*rotation.z + F(2.0)*rotation.y*rotation.w,
F(2.0)*rotation.y*rotation.z - F(2.0)*rotation.x*rotation.w,
F(1.0) - F(2.0)*rotation.x*rotation.x - F(2.0)*rotation.y*rotation.y,
F(0.0),
F(0.0),
F(0.0),
F(0.0),
F(1.0));
} }
template<typename T> template<typename T>
@ -354,17 +343,10 @@ void NzMatrix4<T>::MakeScale(const NzVector3<T>& scale)
template<typename T> template<typename T>
void NzMatrix4<T>::MakeTranslation(const NzVector3<T>& translation) void NzMatrix4<T>::MakeTranslation(const NzVector3<T>& translation)
{ {
#if NAZARA_MATH_MATRIX_COLUMN_MAJOR
Set(F(1.0), F(0.0), F(0.0), F(0.0), Set(F(1.0), F(0.0), F(0.0), F(0.0),
F(0.0), F(1.0), F(0.0), F(0.0), F(0.0), F(1.0), F(0.0), F(0.0),
F(0.0), F(0.0), F(1.0), F(0.0), F(0.0), F(0.0), F(1.0), F(0.0),
translation.x, translation.y, translation.z, F(1.0)); translation.x, translation.y, translation.z, F(1.0));
#else
Set(F(1.0), F(0.0), F(0.0), translation.x,
F(0.0), F(1.0), F(0.0), translation.y,
F(0.0), F(0.0), F(1.0), translation.z,
F(0.0), F(0.0), F(0.0), F(1.0));
#endif
} }
template<typename T> template<typename T>
@ -451,21 +433,12 @@ void NzMatrix4<T>::SetRotation(const NzQuaternion<T>& rotation)
m_sharedMatrix->m22 = F(1.0) - F(2.0)*rotation.x*rotation.x - F(2.0)*rotation.z*rotation.z; m_sharedMatrix->m22 = F(1.0) - F(2.0)*rotation.x*rotation.x - F(2.0)*rotation.z*rotation.z;
m_sharedMatrix->m33 = F(1.0) - F(2.0)*rotation.x*rotation.x - F(2.0)*rotation.y*rotation.y; m_sharedMatrix->m33 = F(1.0) - F(2.0)*rotation.x*rotation.x - F(2.0)*rotation.y*rotation.y;
#if NAZARA_MATH_MATRIX_COLUMN_MAJOR
m_sharedMatrix->m12 = F(2.0)*rotation.x*rotation.y - F(2.0)*rotation.z*rotation.w; m_sharedMatrix->m12 = F(2.0)*rotation.x*rotation.y - F(2.0)*rotation.z*rotation.w;
m_sharedMatrix->m13 = F(2.0)*rotation.x*rotation.z + F(2.0)*rotation.y*rotation.w; m_sharedMatrix->m13 = F(2.0)*rotation.x*rotation.z + F(2.0)*rotation.y*rotation.w;
m_sharedMatrix->m21 = F(2.0)*rotation.x*rotation.y + F(2.0)*rotation.z*rotation.w; m_sharedMatrix->m21 = F(2.0)*rotation.x*rotation.y + F(2.0)*rotation.z*rotation.w;
m_sharedMatrix->m23 = F(2.0)*rotation.y*rotation.z - F(2.0)*rotation.x*rotation.w; m_sharedMatrix->m23 = F(2.0)*rotation.y*rotation.z - F(2.0)*rotation.x*rotation.w;
m_sharedMatrix->m31 = F(2.0)*rotation.x*rotation.z - F(2.0)*rotation.y*rotation.w; m_sharedMatrix->m31 = F(2.0)*rotation.x*rotation.z - F(2.0)*rotation.y*rotation.w;
m_sharedMatrix->m32 = F(2.0)*rotation.y*rotation.z + F(2.0)*rotation.x*rotation.w; m_sharedMatrix->m32 = F(2.0)*rotation.y*rotation.z + F(2.0)*rotation.x*rotation.w;
#else
m_sharedMatrix->m12 = F(2.0)*rotation.x*rotation.y + F(2.0)*rotation.z*rotation.w;
m_sharedMatrix->m13 = F(2.0)*rotation.x*rotation.z - F(2.0)*rotation.y*rotation.w;
m_sharedMatrix->m21 = F(2.0)*rotation.x*rotation.y - F(2.0)*rotation.z*rotation.w;
m_sharedMatrix->m23 = F(2.0)*rotation.y*rotation.z + F(2.0)*rotation.x*rotation.w;
m_sharedMatrix->m31 = F(2.0)*rotation.x*rotation.z + F(2.0)*rotation.y*rotation.w;
m_sharedMatrix->m32 = F(2.0)*rotation.y*rotation.z - F(2.0)*rotation.x*rotation.w;
#endif
} }
template<typename T> template<typename T>
@ -483,17 +456,10 @@ void NzMatrix4<T>::SetTranslation(const NzVector3<T>& translation)
{ {
EnsureOwnership(); EnsureOwnership();
#if NAZARA_MATH_MATRIX_COLUMN_MAJOR
m_sharedMatrix->m41 = translation.x; m_sharedMatrix->m41 = translation.x;
m_sharedMatrix->m42 = translation.y; m_sharedMatrix->m42 = translation.y;
m_sharedMatrix->m43 = translation.z; m_sharedMatrix->m43 = translation.z;
m_sharedMatrix->m44 = F(1.0); m_sharedMatrix->m44 = F(1.0);
#else
m_sharedMatrix->m14 = translation.x;
m_sharedMatrix->m24 = translation.y;
m_sharedMatrix->m34 = translation.z;
m_sharedMatrix->m44 = F(1.0);
#endif
} }
template<typename T> template<typename T>
@ -832,7 +798,6 @@ NzMatrix4<T> NzMatrix4<T>::ConcatenateAffine(const NzMatrix4& m1, const NzMatrix
} }
#endif #endif
#if NAZARA_MATH_MATRIX_COLUMN_MAJOR
return NzMatrix4(m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m11 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m21 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m31, return NzMatrix4(m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m11 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m21 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m31,
m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m32, m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m32,
m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m33, m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m33,
@ -852,27 +817,6 @@ NzMatrix4<T> NzMatrix4<T>::ConcatenateAffine(const NzMatrix4& m1, const NzMatrix
m1.m_sharedMatrix->m41*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m42*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m43*m2.m_sharedMatrix->m32 + m2.m_sharedMatrix->m42, m1.m_sharedMatrix->m41*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m42*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m43*m2.m_sharedMatrix->m32 + m2.m_sharedMatrix->m42,
m1.m_sharedMatrix->m41*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m42*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m43*m2.m_sharedMatrix->m33 + m2.m_sharedMatrix->m43, m1.m_sharedMatrix->m41*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m42*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m43*m2.m_sharedMatrix->m33 + m2.m_sharedMatrix->m43,
F(1.0)); F(1.0));
#else
return NzMatrix4(m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m11 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m21 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m31,
m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m32,
m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m33,
m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m14 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m24 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m34 + m1.m_sharedMatrix->m14,
m1.m_sharedMatrix->m21*m2.m_sharedMatrix->m11 + m1.m_sharedMatrix->m22*m2.m_sharedMatrix->m21 + m1.m_sharedMatrix->m23*m2.m_sharedMatrix->m31,
m1.m_sharedMatrix->m21*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m22*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m23*m2.m_sharedMatrix->m32,
m1.m_sharedMatrix->m21*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m22*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m23*m2.m_sharedMatrix->m33,
m1.m_sharedMatrix->m21*m2.m_sharedMatrix->m14 + m1.m_sharedMatrix->m22*m2.m_sharedMatrix->m24 + m1.m_sharedMatrix->m23*m2.m_sharedMatrix->m34 + m1.m_sharedMatrix->m24,
m1.m_sharedMatrix->m31*m2.m_sharedMatrix->m11 + m1.m_sharedMatrix->m32*m2.m_sharedMatrix->m21 + m1.m_sharedMatrix->m33*m2.m_sharedMatrix->m31,
m1.m_sharedMatrix->m31*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m32*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m33*m2.m_sharedMatrix->m32,
m1.m_sharedMatrix->m31*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m32*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m33*m2.m_sharedMatrix->m33,
m1.m_sharedMatrix->m31*m2.m_sharedMatrix->m14 + m1.m_sharedMatrix->m32*m2.m_sharedMatrix->m24 + m1.m_sharedMatrix->m33*m2.m_sharedMatrix->m34 + m1.m_sharedMatrix->m34,
F(0.0),
F(0.0),
F(0.0),
F(1.0));
#endif
} }
template<typename T> template<typename T>
@ -885,10 +829,10 @@ NzMatrix4<T> NzMatrix4<T>::Identity()
} }
template<typename T> template<typename T>
NzMatrix4<T> NzMatrix4<T>::LookAt(const NzVector3<T>& eye, const NzVector3<T>& center, const NzVector3<T>& up) NzMatrix4<T> NzMatrix4<T>::LookAt(const NzVector3<T>& eye, const NzVector3<T>& target, const NzVector3<T>& up)
{ {
NzMatrix4 matrix; NzMatrix4 matrix;
matrix.MakeLookAt(eye, center, up); matrix.MakeLookAt(eye, target, up);
return matrix; return matrix;
} }

View File

@ -28,7 +28,10 @@ template<typename T> class NzQuaternion
T DotProduct(const NzQuaternion& vec) const; T DotProduct(const NzQuaternion& vec) const;
NzQuaternion GetConjugate() const; NzQuaternion GetConjugate() const;
NzQuaternion GetNormalized() const; NzQuaternion GetInverse() const;
NzQuaternion GetNormal() const;
void Inverse();
void MakeIdentity(); void MakeIdentity();
void MakeZero(); void MakeZero();

View File

@ -67,7 +67,16 @@ NzQuaternion<T> NzQuaternion<T>::GetConjugate() const
} }
template<typename T> template<typename T>
NzQuaternion<T> NzQuaternion<T>::GetNormalized() const NzQuaternion<T> NzQuaternion<T>::GetInverse() const
{
NzQuaternion<T> quat(*this);
quat.Inverse();
return quat;
}
template<typename T>
NzQuaternion<T> NzQuaternion<T>::GetNormal() const
{ {
NzQuaternion<T> quat(*this); NzQuaternion<T> quat(*this);
quat.Normalize(); quat.Normalize();
@ -75,16 +84,31 @@ NzQuaternion<T> NzQuaternion<T>::GetNormalized() const
return quat; return quat;
} }
template<typename T>
void NzQuaternion<T>::Inverse()
{
T norm = SquaredMagnitude();
if (norm > F(0.0))
{
T invNorm = F(1.0) / norm;
w *= invNorm;
x *= -invNorm;
y *= -invNorm;
z *= -invNorm;
}
}
template<typename T> template<typename T>
void NzQuaternion<T>::MakeIdentity() void NzQuaternion<T>::MakeIdentity()
{ {
Set(1.0, 0.0, 0.0, 0.0); Set(F(1.0), F(0.0), F(0.0), F(0.0));
} }
template<typename T> template<typename T>
void NzQuaternion<T>::MakeZero() void NzQuaternion<T>::MakeZero()
{ {
Set(0.0, 0.0, 0.0, 0.0); Set(F(0.0), F(0.0), F(0.0), F(0.0));
} }
template<typename T> template<typename T>
@ -98,16 +122,18 @@ T NzQuaternion<T>::Normalize()
{ {
T squaredMagnitude = SquaredMagnitude(); T squaredMagnitude = SquaredMagnitude();
if (squaredMagnitude-F(1.0) > std::numeric_limits<T>::epsilon()) // Inutile de vérifier si la magnitude au carrée est négative (Elle ne peut pas l'être)
if (!NzNumberEquals(squaredMagnitude, F(1.0)))
{ {
T magnitude = std::sqrt(squaredMagnitude); T norm = std::sqrt(squaredMagnitude);
T invNorm = F(1.0) / norm;
w /= magnitude; w *= invNorm;
x /= magnitude; x *= invNorm;
y /= magnitude; y *= invNorm;
z /= magnitude; z *= invNorm;
return magnitude; return norm;
} }
else else
return F(1.0); // Le quaternion est déjà normalisé return F(1.0); // Le quaternion est déjà normalisé
@ -132,20 +158,24 @@ void NzQuaternion<T>::Set(T quat[4])
} }
template<typename T> template<typename T>
void NzQuaternion<T>::Set(T angle, const NzVector3<T>& normalizedAxis) void NzQuaternion<T>::Set(T angle, const NzVector3<T>& axis)
{ {
angle /= F(2.0);
#if !NAZARA_MATH_ANGLE_RADIAN #if !NAZARA_MATH_ANGLE_RADIAN
angle = NzDegreeToRadian(angle); angle = NzDegreeToRadian(angle);
#endif #endif
angle /= 2; NzVector3<T> normalizedAxis = axis.GetNormal();
auto sinAngle = std::sin(angle); T sinAngle = std::sin(angle);
w = std::cos(angle); w = std::cos(angle);
x = normalizedAxis.x * sinAngle; x = normalizedAxis.x * sinAngle;
y = normalizedAxis.y * sinAngle; y = normalizedAxis.y * sinAngle;
z = normalizedAxis.z * sinAngle; z = normalizedAxis.z * sinAngle;
Normalize();
} }
template<typename T> template<typename T>
@ -190,12 +220,8 @@ NzEulerAngles<T> NzQuaternion<T>::ToEulerAngles() const
if (test < F(-0.499)) if (test < F(-0.499))
return NzEulerAngles<T>(NzDegrees(F(-90.0)), NzRadians(F(-2.0) * std::atan2(x, w)), F(0.0)); return NzEulerAngles<T>(NzDegrees(F(-90.0)), NzRadians(F(-2.0) * std::atan2(x, w)), F(0.0));
T xx = x*x; return NzEulerAngles<T>(NzRadians(std::atan2(F(2.0)*x*w - F(2.0)*y*z, F(1.0) - F(2.0)*x* - F(2.0)*z*z)),
T yy = y*y; NzRadians(std::atan2(F(2.0)*y*w - F(2.0)*x*z, F(1.0) - F(2.0)*y*y - F(2.0)*z*z)),
T zz = z*z;
return NzEulerAngles<T>(NzRadians(std::atan2(F(2.0)*x*w - F(2.0)*y*z, F(1.0) - F(2.0)*xx - F(2.0)*zz)),
NzRadians(std::atan2(F(2.0)*y*w - F(2.0)*x*z, F(1.0) - F(2.0)*yy - F(2.0)*zz)),
NzRadians(std::asin(F(2.0)*test))); NzRadians(std::asin(F(2.0)*test)));
} }
@ -242,14 +268,13 @@ NzQuaternion<T> NzQuaternion<T>::operator*(const NzQuaternion& quat) const
template<typename T> template<typename T>
NzVector3<T> NzQuaternion<T>::operator*(const NzVector3<T>& vec) const NzVector3<T> NzQuaternion<T>::operator*(const NzVector3<T>& vec) const
{ {
NzVector3<T> normal(vec); NzVector3f quatVec(x, y, z);
normal.Normalize(); NzVector3f uv = quatVec.CrossProduct(vec);
NzVector3f uuv = quatVec.CrossProduct(uv);
NzQuaternion qvec(0.0, normal.x, normal.y, normal.z); uv *= F(2.0) * w;
NzQuaternion result(operator*(qvec * GetConjugate())); uuv *= F(2.0);
return NzVector3<T>(result.x, result.y, result.z);
return vec + uv + uuv;
} }
template<typename T> template<typename T>

View File

@ -29,14 +29,15 @@ template<typename T> class NzVector2
NzVector2 GetNormal() const; NzVector2 GetNormal() const;
void MakeCeil(const NzVector2& vec); T Length() const;
void MakeFloor(const NzVector2& vec); float Lengthf() const;
void MakeUnitX(); void MakeUnitX();
void MakeUnitY(); void MakeUnitY();
void MakeZero(); void MakeZero();
T Length() const; void Maximize(const NzVector2& vec);
float Lengthf() const; void Minimize(const NzVector2& vec);
void Normalize(); void Normalize();

View File

@ -99,26 +99,6 @@ float NzVector2<T>::Lengthf() const
return std::sqrt(static_cast<float>(SquaredLength())); return std::sqrt(static_cast<float>(SquaredLength()));
} }
template<typename T>
void NzVector2<T>::MakeCeil(const NzVector2& vec)
{
if (vec.x > x)
x = vec.x;
if (vec.y > y)
y = vec.y;
}
template<typename T>
void NzVector2<T>::MakeFloor(const NzVector2& vec)
{
if (vec.x < x)
x = vec.x;
if (vec.y < y)
y = vec.y;
}
template<typename T> template<typename T>
void NzVector2<T>::MakeUnitX() void NzVector2<T>::MakeUnitX()
{ {
@ -137,6 +117,26 @@ void NzVector2<T>::MakeZero()
Set(F(0.0), F(0.0)); Set(F(0.0), F(0.0));
} }
template<typename T>
void NzVector2<T>::Maximize(const NzVector2& vec)
{
if (vec.x > x)
x = vec.x;
if (vec.y > y)
y = vec.y;
}
template<typename T>
void NzVector2<T>::Minimize(const NzVector2& vec)
{
if (vec.x < x)
x = vec.x;
if (vec.y < y)
y = vec.y;
}
template<typename T> template<typename T>
void NzVector2<T>::Normalize() void NzVector2<T>::Normalize()
{ {

View File

@ -36,13 +36,17 @@ template<typename T> class NzVector3
T Length() const; T Length() const;
float Lengthf() const; float Lengthf() const;
void MakeCeil(const NzVector3& vec); void MakeForward();
void MakeFloor(const NzVector3& vec); void MakeLeft();
void MakeUnitX(); void MakeUnitX();
void MakeUnitY(); void MakeUnitY();
void MakeUnitZ(); void MakeUnitZ();
void MakeUp();
void MakeZero(); void MakeZero();
void Maximize(const NzVector3& vec);
void Minimize(const NzVector3& vec);
void Normalize(); void Normalize();
void Set(T X, T Y, T Z); void Set(T X, T Y, T Z);
@ -88,9 +92,15 @@ template<typename T> class NzVector3
bool operator>(const NzVector3& vec) const; bool operator>(const NzVector3& vec) const;
bool operator>=(const NzVector3& vec) const; bool operator>=(const NzVector3& vec) const;
static NzVector3 CrossProduct(const NzVector3& vec1, const NzVector3& vec2);
static T DotProduct(const NzVector3& vec1, const NzVector3& vec2);
static NzVector3 Forward();
static NzVector3 Left();
static NzVector3 Normalize(const NzVector3& vec);
static NzVector3 UnitX(); static NzVector3 UnitX();
static NzVector3 UnitY(); static NzVector3 UnitY();
static NzVector3 UnitZ(); static NzVector3 UnitZ();
static NzVector3 Up();
static NzVector3 Zero(); static NzVector3 Zero();
T x, y, z; T x, y, z;

View File

@ -69,7 +69,7 @@ inline unsigned int NzVector3<unsigned int>::AbsDotProduct(const NzVector3<unsig
template<typename T> template<typename T>
NzVector3<T> NzVector3<T>::CrossProduct(const NzVector3& vec) const NzVector3<T> NzVector3<T>::CrossProduct(const NzVector3& vec) const
{ {
return NzVector3(y * vec.z - z * vec.y, z * vec.x - x * vec.y, x * vec.y - y * vec.x); return NzVector3(y * vec.z - z * vec.y, z * vec.x - x * vec.z, x * vec.y - y * vec.x);
} }
template<typename T> template<typename T>
@ -100,29 +100,27 @@ NzVector3<T> NzVector3<T>::GetNormal() const
} }
template<typename T> template<typename T>
void NzVector3<T>::MakeCeil(const NzVector3& vec) T NzVector3<T>::Length() const
{ {
if (vec.x > x) return std::sqrt(SquaredLength());
x = vec.x;
if (vec.y > y)
y = vec.y;
if (vec.z > z)
z = vec.z;
} }
template<typename T> template<typename T>
void NzVector3<T>::MakeFloor(const NzVector3& vec) float NzVector3<T>::Lengthf() const
{ {
if (vec.x < x) return std::sqrt(static_cast<float>(SquaredLength()));
x = vec.x; }
if (vec.y < y) template<typename T>
y = vec.y; void NzVector3<T>::MakeForward()
{
Set(F(0.0), F(0.0), F(-1.0));
}
if (vec.z < z) template<typename T>
z = vec.z; void NzVector3<T>::MakeLeft()
{
Set(F(-1.0), F(0.0), F(0.0));
} }
template<typename T> template<typename T>
@ -143,6 +141,12 @@ void NzVector3<T>::MakeUnitZ()
Set(F(0.0), F(0.0), F(1.0)); Set(F(0.0), F(0.0), F(1.0));
} }
template<typename T>
void NzVector3<T>::MakeUp()
{
Set(F(0.0), F(1.0), F(0.0));
}
template<typename T> template<typename T>
void NzVector3<T>::MakeZero() void NzVector3<T>::MakeZero()
{ {
@ -150,15 +154,29 @@ void NzVector3<T>::MakeZero()
} }
template<typename T> template<typename T>
T NzVector3<T>::Length() const void NzVector3<T>::Maximize(const NzVector3& vec)
{ {
return std::sqrt(SquaredLength()); if (vec.x > x)
x = vec.x;
if (vec.y > y)
y = vec.y;
if (vec.z > z)
z = vec.z;
} }
template<typename T> template<typename T>
float NzVector3<T>::Lengthf() const void NzVector3<T>::Minimize(const NzVector3& vec)
{ {
return std::sqrt(static_cast<float>(SquaredLength())); if (vec.x < x)
x = vec.x;
if (vec.y < y)
y = vec.y;
if (vec.z < z)
z = vec.z;
} }
template<typename T> template<typename T>
@ -166,13 +184,13 @@ void NzVector3<T>::Normalize()
{ {
T squaredLength = SquaredLength(); T squaredLength = SquaredLength();
if (squaredLength-F(1.0) > std::numeric_limits<T>::epsilon()) if (!NzNumberEquals(squaredLength, F(1.0)))
{ {
T length = std::sqrt(squaredLength); T invLength = F(1.0) / std::sqrt(squaredLength);
x /= length; x *= invLength;
y /= length; y *= invLength;
z /= length; z *= invLength;
} }
} }
@ -467,6 +485,42 @@ bool NzVector3<T>::operator>=(const NzVector3& vec) const
return !operator<(vec); return !operator<(vec);
} }
template<typename T>
NzVector3<T> NzVector3<T>::CrossProduct(const NzVector3& vec1, const NzVector3& vec2)
{
return vec1.CrossProduct(vec2);
}
template<typename T>
T NzVector3<T>::DotProduct(const NzVector3& vec1, const NzVector3& vec2)
{
return vec1.DotProduct(vec2);
}
template<typename T>
NzVector3<T> NzVector3<T>::Forward()
{
NzVector3 vector;
vector.MakeForward();
return vector;
}
template<typename T>
NzVector3<T> NzVector3<T>::Left()
{
NzVector3 vector;
vector.MakeLeft();
return vector;
}
template<typename T>
NzVector3<T> NzVector3<T>::Normalize(const NzVector3& vec)
{
return vec.GetNormal();
}
template<typename T> template<typename T>
NzVector3<T> NzVector3<T>::UnitX() NzVector3<T> NzVector3<T>::UnitX()
{ {
@ -494,6 +548,15 @@ NzVector3<T> NzVector3<T>::UnitZ()
return vector; return vector;
} }
template<typename T>
NzVector3<T> NzVector3<T>::Up()
{
NzVector3 vector;
vector.MakeUp();
return vector;
}
template<typename T> template<typename T>
NzVector3<T> NzVector3<T>::Zero() NzVector3<T> NzVector3<T>::Zero()
{ {

View File

@ -26,13 +26,14 @@ template<typename T> class NzVector4
T DotProduct(const NzVector4& vec) const; T DotProduct(const NzVector4& vec) const;
void MakeCeil(const NzVector4& vec);
void MakeFloor(const NzVector4& vec);
void MakeUnitX(); void MakeUnitX();
void MakeUnitY(); void MakeUnitY();
void MakeUnitZ(); void MakeUnitZ();
void MakeZero(); void MakeZero();
void Maximize(const NzVector4& vec);
void Minimize(const NzVector4& vec);
void Normalize(); void Normalize();
void Set(T X, T Y, T Z, T W = 1.0); void Set(T X, T Y, T Z, T W = 1.0);

View File

@ -73,38 +73,6 @@ T NzVector4<T>::DotProduct(const NzVector4& vec) const
return x*vec.x + y*vec.y + z*vec.z + w*vec.w; return x*vec.x + y*vec.y + z*vec.z + w*vec.w;
} }
template<typename T>
void NzVector4<T>::MakeCeil(const NzVector4& vec)
{
if (vec.x > x)
x = vec.x;
if (vec.y > y)
y = vec.y;
if (vec.z > z)
z = vec.z;
if (vec.w > w)
w = vec.w;
}
template<typename T>
void NzVector4<T>::MakeFloor(const NzVector4& vec)
{
if (vec.x < x)
x = vec.x;
if (vec.y < y)
y = vec.y;
if (vec.z < z)
z = vec.z;
if (vec.w < w)
w = vec.w;
}
template<typename T> template<typename T>
void NzVector4<T>::MakeUnitX() void NzVector4<T>::MakeUnitX()
{ {
@ -129,6 +97,38 @@ void NzVector4<T>::MakeZero()
Set(F(0.0), F(0.0), F(0.0), F(0.0)); Set(F(0.0), F(0.0), F(0.0), F(0.0));
} }
template<typename T>
void NzVector4<T>::Maximize(const NzVector4& vec)
{
if (vec.x > x)
x = vec.x;
if (vec.y > y)
y = vec.y;
if (vec.z > z)
z = vec.z;
if (vec.w > w)
w = vec.w;
}
template<typename T>
void NzVector4<T>::Minimize(const NzVector4& vec)
{
if (vec.x < x)
x = vec.x;
if (vec.y < y)
y = vec.y;
if (vec.z < z)
z = vec.z;
if (vec.w < w)
w = vec.w;
}
template<typename T> template<typename T>
void NzVector4<T>::Normalize() void NzVector4<T>::Normalize()
{ {

View File

@ -35,6 +35,7 @@
#include <Nazara/Renderer/Renderer.hpp> #include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/RenderTarget.hpp> #include <Nazara/Renderer/RenderTarget.hpp>
#include <Nazara/Renderer/RenderTargetParameters.hpp> #include <Nazara/Renderer/RenderTargetParameters.hpp>
#include <Nazara/Renderer/RenderTexture.hpp>
#include <Nazara/Renderer/RenderWindow.hpp> #include <Nazara/Renderer/RenderWindow.hpp>
#include <Nazara/Renderer/Shader.hpp> #include <Nazara/Renderer/Shader.hpp>
#include <Nazara/Renderer/Texture.hpp> #include <Nazara/Renderer/Texture.hpp>

View File

@ -29,9 +29,6 @@
/// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci /// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci
// Active une fenêtre de rendu (NzRenderWindow) lors de sa création
#define NAZARA_RENDERER_ACTIVATE_RENDERWINDOW_ON_CREATION 1
// Utilise un tracker pour repérer les éventuels leaks (Ralentit l'exécution) // Utilise un tracker pour repérer les éventuels leaks (Ralentit l'exécution)
#define NAZARA_RENDERER_MEMORYLEAKTRACKER 0 #define NAZARA_RENDERER_MEMORYLEAKTRACKER 0

View File

@ -2,20 +2,19 @@
// This file is part of the "Nazara Engine - Renderer module" // This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#ifdef NAZARA_RENDERER_COMMON
#error This file is not part of the common renderer interface, you must undefine NAZARA_RENDERER_COMMON to use it
#endif
#pragma once #pragma once
#ifndef NAZARA_CONTEXT_HPP #ifndef NAZARA_CONTEXT_HPP
#define NAZARA_CONTEXT_HPP #define NAZARA_CONTEXT_HPP
#ifdef NAZARA_RENDERER_OPENGL
#include <Nazara/Core/Resource.hpp>
#include <Nazara/Renderer/ContextParameters.hpp> #include <Nazara/Renderer/ContextParameters.hpp>
class NzContextImpl; class NzContextImpl;
class NAZARA_API NzContext class NAZARA_API NzContext : public NzResource
{ {
friend NzContextImpl; friend NzContextImpl;
@ -25,6 +24,7 @@ class NAZARA_API NzContext
bool Create(const NzContextParameters& parameters = NzContextParameters()); bool Create(const NzContextParameters& parameters = NzContextParameters());
void Destroy(); void Destroy();
const NzContextParameters& GetParameters() const; const NzContextParameters& GetParameters() const;
bool IsActive() const; bool IsActive() const;
bool SetActive(bool active); bool SetActive(bool active);
@ -44,4 +44,6 @@ class NAZARA_API NzContext
static NzContext* s_reference; static NzContext* s_reference;
}; };
#endif // NAZARA_RENDERER_OPENGL
#endif // NAZARA_CONTEXT_HPP #endif // NAZARA_CONTEXT_HPP

View File

@ -7,6 +7,16 @@
#ifndef NAZARA_ENUMS_RENDERER_HPP #ifndef NAZARA_ENUMS_RENDERER_HPP
#define NAZARA_ENUMS_RENDERER_HPP #define NAZARA_ENUMS_RENDERER_HPP
enum nzAttachmentPoint
{
nzAttachmentPoint_Color,
nzAttachmentPoint_Depth,
nzAttachmentPoint_DepthStencil,
nzAttachmentPoint_Stencil,
nzAttachmentPoint_Max = nzAttachmentPoint_Stencil
};
enum nzBlendFunc enum nzBlendFunc
{ {
nzBlendFunc_DestAlpha, nzBlendFunc_DestAlpha,
@ -18,21 +28,27 @@ enum nzBlendFunc
nzBlendFunc_InvSrcAlpha, nzBlendFunc_InvSrcAlpha,
nzBlendFunc_InvSrcColor, nzBlendFunc_InvSrcColor,
nzBlendFunc_One, nzBlendFunc_One,
nzBlendFunc_Zero nzBlendFunc_Zero,
nzBlendFunc_Max = nzBlendFunc_Zero
}; };
enum nzFaceCulling enum nzFaceCulling
{ {
nzFaceCulling_Back, nzFaceCulling_Back,
nzFaceCulling_Front, nzFaceCulling_Front,
nzFaceCulling_FrontAndBack nzFaceCulling_FrontAndBack,
nzFaceCulling_Max = nzFaceCulling_FrontAndBack
}; };
enum nzFaceFilling enum nzFaceFilling
{ {
nzFaceFilling_Point, nzFaceFilling_Point,
nzFaceFilling_Line, nzFaceFilling_Line,
nzFaceFilling_Fill nzFaceFilling_Fill,
nzFaceFilling_Max = nzFaceFilling_Fill
}; };
enum nzMatrixType enum nzMatrixType
@ -47,7 +63,9 @@ enum nzMatrixType
enum nzPixelBufferType enum nzPixelBufferType
{ {
nzPixelBufferType_Pack, nzPixelBufferType_Pack,
nzPixelBufferType_Unpack nzPixelBufferType_Unpack,
nzPixelBufferType_Max = nzPixelBufferType_Unpack
}; };
enum nzRendererCap enum nzRendererCap
@ -58,6 +76,7 @@ enum nzRendererCap
nzRendererCap_MultipleRenderTargets, nzRendererCap_MultipleRenderTargets,
nzRendererCap_OcclusionQuery, nzRendererCap_OcclusionQuery,
nzRendererCap_PixelBufferObject, nzRendererCap_PixelBufferObject,
nzRendererCap_RenderTexture,
nzRendererCap_Texture3D, nzRendererCap_Texture3D,
nzRendererCap_TextureCubemap, nzRendererCap_TextureCubemap,
nzRendererCap_TextureMulti, nzRendererCap_TextureMulti,
@ -66,7 +85,7 @@ enum nzRendererCap
nzRendererCap_Max = nzRendererCap_TextureNPOT nzRendererCap_Max = nzRendererCap_TextureNPOT
}; };
enum nzRendererClear enum nzRendererClearFlags
{ {
nzRendererClear_Color = 0x01, nzRendererClear_Color = 0x01,
nzRendererClear_Depth = 0x02, nzRendererClear_Depth = 0x02,
@ -81,7 +100,9 @@ enum nzRendererComparison
nzRendererComparison_GreaterOrEqual, nzRendererComparison_GreaterOrEqual,
nzRendererComparison_Less, nzRendererComparison_Less,
nzRendererComparison_LessOrEqual, nzRendererComparison_LessOrEqual,
nzRendererComparison_Never nzRendererComparison_Never,
nzRendererComparison_Max = nzRendererComparison_Never
}; };
enum nzRendererParameter enum nzRendererParameter
@ -91,15 +112,19 @@ enum nzRendererParameter
nzRendererParameter_DepthTest, nzRendererParameter_DepthTest,
nzRendererParameter_DepthWrite, nzRendererParameter_DepthWrite,
nzRendererParameter_FaceCulling, nzRendererParameter_FaceCulling,
nzRendererParameter_Stencil nzRendererParameter_Stencil,
nzRendererParameter_Max = nzRendererParameter_Stencil
}; };
enum nzShaderLanguage enum nzShaderLanguage
{ {
nzShaderLanguage_Unknown, nzShaderLanguage_Unknown = -1,
nzShaderLanguage_Cg, nzShaderLanguage_Cg,
nzShaderLanguage_GLSL nzShaderLanguage_GLSL,
nzShaderLanguage_Max = nzShaderLanguage_GLSL
}; };
enum nzShaderType enum nzShaderType
@ -120,22 +145,30 @@ enum nzStencilOperation
nzStencilOperation_Invert, nzStencilOperation_Invert,
nzStencilOperation_Keep, nzStencilOperation_Keep,
nzStencilOperation_Replace, nzStencilOperation_Replace,
nzStencilOperation_Zero nzStencilOperation_Zero,
nzStencilOperation_Max = nzStencilOperation_Zero
}; };
enum nzTextureFilter enum nzTextureFilter
{ {
nzTextureFilter_Unknown = -1,
nzTextureFilter_Bilinear, nzTextureFilter_Bilinear,
nzTextureFilter_Nearest, nzTextureFilter_Nearest,
nzTextureFilter_Trilinear, nzTextureFilter_Trilinear,
nzTextureFilter_Unknown
nzTextureFilter_Max = nzTextureFilter_Trilinear
}; };
enum nzTextureWrap enum nzTextureWrap
{ {
nzTextureWrap_Unknown = -1,
nzTextureWrap_Clamp, nzTextureWrap_Clamp,
nzTextureWrap_Repeat, nzTextureWrap_Repeat,
nzTextureWrap_Unknown
nzTextureWrap_Max = nzTextureWrap_Repeat
}; };
#endif // NAZARA_ENUMS_RENDERER_HPP #endif // NAZARA_ENUMS_RENDERER_HPP

View File

@ -2,19 +2,19 @@
// This file is part of the "Nazara Engine - Renderer module" // This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#ifdef NAZARA_RENDERER_COMMON
#error This file is not part of the common renderer interface, you must undefine NAZARA_RENDERER_COMMON to use it
#endif
#pragma once #pragma once
#ifndef NAZARA_OPENGL_HPP #ifndef NAZARA_OPENGL_HPP
#define NAZARA_OPENGL_HPP #define NAZARA_OPENGL_HPP
#ifdef NAZARA_RENDERER_OPENGL
// gl3.h définit WIN32_LEAN_AND_MEAN qui entre en conflit avec la définition de Nazara et doit donc être inclut en premier // gl3.h définit WIN32_LEAN_AND_MEAN qui entre en conflit avec la définition de Nazara et doit donc être inclut en premier
#include <GL3/glcorearb.h> #include <GL3/glcorearb.h>
#include <Nazara/Prerequesites.hpp> #include <Nazara/Prerequesites.hpp>
#include <Nazara/Core/String.hpp> #include <Nazara/Core/String.hpp>
#include <Nazara/Utility/Enums.hpp>
#include <Nazara/Renderer/Enums.hpp>
// Inclusion des extensions // Inclusion des extensions
#include <GL3/glext.h> #include <GL3/glext.h>
@ -24,42 +24,77 @@
#include <GL3/glxext.h> #include <GL3/glxext.h>
#endif #endif
enum nzOpenGLExtension
{
nzOpenGLExtension_AnisotropicFilter,
nzOpenGLExtension_DebugOutput,
nzOpenGLExtension_FP64,
nzOpenGLExtension_FrameBufferObject,
nzOpenGLExtension_PixelBufferObject,
nzOpenGLExtension_SeparateShaderObjects,
nzOpenGLExtension_TextureArray,
nzOpenGLExtension_TextureCompression_s3tc,
nzOpenGLExtension_TextureStorage,
nzOpenGLExtension_VertexArrayObject,
nzOpenGLExtension_Max = nzOpenGLExtension_VertexArrayObject
};
using NzOpenGLFunc = void (*)(); using NzOpenGLFunc = void (*)();
class NAZARA_API NzOpenGL namespace NzOpenGL
{ {
public: enum FormatType
enum Extension
{ {
AnisotropicFilter, FormatType_RenderBuffer,
DebugOutput, // FormatType_MultisampleTexture,
FP64, FormatType_Texture
FrameBufferObject,
PixelBufferObject,
SeparateShaderObjects,
Texture3D,
TextureArray,
TextureCompression_s3tc,
TextureStorage,
VertexArrayObject,
Max = VertexArrayObject
}; };
static NzOpenGLFunc GetEntry(const NzString& entryPoint); struct Format
static unsigned int GetVersion(); {
static bool Initialize(); GLenum dataFormat;
static bool IsSupported(Extension extension); GLenum dataType;
static bool IsSupported(const NzString& string); GLint internalFormat;
static void Uninitialize();
}; };
NzOpenGLFunc GetEntry(const NzString& entryPoint);
unsigned int GetVersion();
bool Initialize();
bool IsSupported(nzOpenGLExtension extension);
bool IsSupported(const NzString& string);
bool TranslateFormat(nzPixelFormat pixelFormat, Format* format, FormatType target);
void Uninitialize();
extern GLenum Attachment[nzAttachmentPoint_Max+1];
extern nzUInt8 AttributeIndex[nzElementUsage_Max+1];
extern GLenum BlendFunc[nzBlendFunc_Max+1];
extern GLenum BufferLock[nzBufferAccess_Max+1];
extern GLenum BufferLockRange[nzBufferAccess_Max+1];
extern GLenum BufferTarget[nzBufferType_Max+1];
extern GLenum BufferTargetBinding[nzBufferType_Max+1];
extern GLenum BufferUsage[nzBufferUsage_Max+1];
extern GLenum CubemapFace[6]; // Un cube possède six faces et ça n'est pas prêt de changer
extern GLenum ElementType[nzElementType_Max+1];
extern GLenum FaceCulling[nzFaceCulling_Max+1];
extern GLenum FaceFilling[nzFaceFilling_Max+1];
extern GLenum PrimitiveType[nzPrimitiveType_Max+1];
extern GLenum RendererComparison[nzRendererComparison_Max+1];
extern GLenum RendererParameter[nzRendererParameter_Max+1];
extern GLenum ShaderType[nzShaderType_Max+1];
extern GLenum StencilOperation[nzStencilOperation_Max+1];
extern GLenum TextureTarget[nzImageType_Max+1];
extern GLenum TextureTargetBinding[nzImageType_Max+1];
extern GLenum TextureTargetProxy[nzImageType_Max+1];
}
NAZARA_API extern PFNGLACTIVETEXTUREPROC glActiveTexture; NAZARA_API extern PFNGLACTIVETEXTUREPROC glActiveTexture;
NAZARA_API extern PFNGLATTACHSHADERPROC glAttachShader; NAZARA_API extern PFNGLATTACHSHADERPROC glAttachShader;
NAZARA_API extern PFNGLBEGINQUERYPROC glBeginQuery; NAZARA_API extern PFNGLBEGINQUERYPROC glBeginQuery;
NAZARA_API extern PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation; NAZARA_API extern PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
NAZARA_API extern PFNGLBINDBUFFERPROC glBindBuffer; NAZARA_API extern PFNGLBINDBUFFERPROC glBindBuffer;
NAZARA_API extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; NAZARA_API extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
NAZARA_API extern PFNGLBINDFRAGDATALOCATIONPROC glBindFragDataLocation;
NAZARA_API extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; NAZARA_API extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
NAZARA_API extern PFNGLBINDTEXTUREPROC glBindTexture; NAZARA_API extern PFNGLBINDTEXTUREPROC glBindTexture;
NAZARA_API extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray; NAZARA_API extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
@ -99,7 +134,11 @@ NAZARA_API extern PFNGLDRAWELEMENTSPROC glDrawElements;
NAZARA_API extern PFNGLENDQUERYPROC glEndQuery; NAZARA_API extern PFNGLENDQUERYPROC glEndQuery;
NAZARA_API extern PFNGLFLUSHPROC glFlush; NAZARA_API extern PFNGLFLUSHPROC glFlush;
NAZARA_API extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer; NAZARA_API extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
NAZARA_API extern PFNGLFRAMEBUFFERTEXTUREPROC glFramebufferTexture;
NAZARA_API extern PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D;
NAZARA_API extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; NAZARA_API extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
NAZARA_API extern PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D;
NAZARA_API extern PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer;
NAZARA_API extern PFNGLENABLEPROC glEnable; NAZARA_API extern PFNGLENABLEPROC glEnable;
NAZARA_API extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; NAZARA_API extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
NAZARA_API extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap; NAZARA_API extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
@ -189,4 +228,6 @@ NAZARA_API extern PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs;
NAZARA_API extern PFNGLXSWAPINTERVALSGIPROC glXSwapInterval; NAZARA_API extern PFNGLXSWAPINTERVALSGIPROC glXSwapInterval;
#endif #endif
#endif // NAZARA_RENDERER_OPENGL
#endif // NAZARA_OPENGL_HPP #endif // NAZARA_OPENGL_HPP

View File

@ -21,19 +21,18 @@ class NAZARA_API NzRenderTarget
NzRenderTarget() = default; NzRenderTarget() = default;
virtual ~NzRenderTarget(); virtual ~NzRenderTarget();
#ifndef NAZARA_RENDERER_COMMON
virtual bool HasContext() const = 0;
#endif
virtual unsigned int GetHeight() const = 0; virtual unsigned int GetHeight() const = 0;
virtual NzRenderTargetParameters GetParameters() const = 0; virtual NzRenderTargetParameters GetParameters() const = 0;
virtual unsigned int GetWidth() const = 0; virtual unsigned int GetWidth() const = 0;
bool IsActive() const; bool IsActive() const;
virtual bool IsValid() const = 0; virtual bool IsRenderable() const = 0;
bool SetActive(bool active); bool SetActive(bool active);
// Fonctions OpenGL
virtual bool HasContext() const = 0;
protected: protected:
virtual bool Activate() = 0; virtual bool Activate() = 0;
virtual void Desactivate(); virtual void Desactivate();

View File

@ -0,0 +1,60 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_RENDERTEXTURE_HPP
#define NAZARA_RENDERTEXTURE_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Core/NonCopyable.hpp>
#include <Nazara/Core/ResourceListener.hpp>
#include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/RenderTarget.hpp>
#include <Nazara/Renderer/Texture.hpp>
struct NzRenderTextureImpl;
class NAZARA_API NzRenderTexture : public NzRenderTarget, NzResourceListener, NzNonCopyable
{
public:
NzRenderTexture() = default;
~NzRenderTexture();
bool AttachBuffer(nzAttachmentPoint attachmentPoint, nzUInt8 index, nzPixelFormat format);
bool AttachTexture(nzAttachmentPoint attachmentPoint, nzUInt8 index, NzTexture* texture);
bool AttachTexture(nzAttachmentPoint attachmentPoint, nzUInt8 index, NzTexture* texture, unsigned int z);
bool Create(unsigned int width, unsigned int height, bool lock = false);
void Destroy();
void Detach(nzAttachmentPoint attachmentPoint, nzUInt8 index);
unsigned int GetHeight() const;
NzRenderTargetParameters GetParameters() const;
unsigned int GetWidth() const;
bool IsComplete() const;
bool IsRenderable() const;
bool IsValid() const;
bool Lock() const;
void Unlock() const;
// Fonctions OpenGL
bool HasContext() const;
static bool IsSupported();
protected:
bool Activate() override;
void Desactivate() override;
private:
void OnResourceDestroy(const NzResource* resource, int index) override;
NzRenderTextureImpl* m_impl = nullptr;
};
#endif // NAZARA_RENDERTEXTURE_HPP

View File

@ -39,28 +39,25 @@ class NAZARA_API NzRenderWindow : public NzRenderTarget, public NzWindow
void EnableVerticalSync(bool enabled); void EnableVerticalSync(bool enabled);
#ifndef NAZARA_RENDERER_COMMON
NzContextParameters GetContextParameters() const;
#endif
unsigned int GetHeight() const; unsigned int GetHeight() const;
NzRenderTargetParameters GetParameters() const; NzRenderTargetParameters GetParameters() const;
unsigned int GetWidth() const; unsigned int GetWidth() const;
#ifndef NAZARA_RENDERER_COMMON bool IsRenderable() const;
bool HasContext() const;
#endif
bool IsValid() const; bool IsValid() const;
void SetFramerateLimit(unsigned int limit); void SetFramerateLimit(unsigned int limit);
// Fonctions OpenGL
NzContextParameters GetContextParameters() const;
bool HasContext() const;
protected: protected:
virtual bool Activate() override; bool Activate() override;
private: private:
virtual void OnWindowDestroying() override; bool OnWindowCreated() override;
virtual bool OnWindowCreated() override; void OnWindowDestroy() override;
NzClock m_clock; NzClock m_clock;
NzContextParameters m_parameters; NzContextParameters m_parameters;

View File

@ -13,10 +13,12 @@
#include <Nazara/Utility/Image.hpp> #include <Nazara/Utility/Image.hpp>
#include <Nazara/Utility/PixelFormat.hpp> #include <Nazara/Utility/PixelFormat.hpp>
class NzRenderTexture;
struct NzTextureImpl; struct NzTextureImpl;
class NAZARA_API NzTexture : public NzResource, NzNonCopyable class NAZARA_API NzTexture : public NzResource, NzNonCopyable
{ {
friend NzRenderTexture;
friend class NzShader; friend class NzShader;
public: public:
@ -24,10 +26,6 @@ class NAZARA_API NzTexture : public NzResource, NzNonCopyable
explicit NzTexture(const NzImage& image); explicit NzTexture(const NzImage& image);
~NzTexture(); ~NzTexture();
#ifndef NAZARA_RENDERER_COMMON
bool Bind() const;
#endif
bool Create(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth = 1, nzUInt8 levelCount = 1, bool lock = false); bool Create(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth = 1, nzUInt8 levelCount = 1, bool lock = false);
void Destroy(); void Destroy();
@ -75,13 +73,18 @@ class NAZARA_API NzTexture : public NzResource, NzNonCopyable
void Unlock(); void Unlock();
// Fonctions OpenGL
unsigned int GetOpenGLID() const;
bool Prepare() const;
static unsigned int GetValidSize(unsigned int size); static unsigned int GetValidSize(unsigned int size);
static bool IsFormatSupported(nzPixelFormat format); static bool IsFormatSupported(nzPixelFormat format);
static bool IsMipmappingSupported(); static bool IsMipmappingSupported();
static bool IsTypeSupported(nzImageType type); static bool IsTypeSupported(nzImageType type);
private: private:
void SetTarget(bool isTarget); NzRenderTexture* GetRenderTexture() const;
void SetRenderTexture(NzRenderTexture* renderTexture);
NzTextureImpl* m_impl; NzTextureImpl* m_impl;
}; };

View File

@ -43,7 +43,7 @@ class NAZARA_API NzAnimation : public NzResource
NzAnimation() = default; NzAnimation() = default;
~NzAnimation(); ~NzAnimation();
unsigned int AddSequence(const NzSequence& sequence); bool AddSequence(const NzSequence& sequence);
bool Create(nzAnimationType type, unsigned int frameCount); bool Create(nzAnimationType type, unsigned int frameCount);
void Destroy(); void Destroy();
@ -54,6 +54,7 @@ class NAZARA_API NzAnimation : public NzResource
const NzSequence* GetSequence(const NzString& sequenceName) const; const NzSequence* GetSequence(const NzString& sequenceName) const;
const NzSequence* GetSequence(unsigned int index) const; const NzSequence* GetSequence(unsigned int index) const;
unsigned int GetSequenceCount() const; unsigned int GetSequenceCount() const;
int GetSequenceIndex(const NzString& sequenceName) const;
nzAnimationType GetType() const; nzAnimationType GetType() const;
bool HasSequence(const NzString& sequenceName) const; bool HasSequence(const NzString& sequenceName) const;

View File

@ -11,7 +11,9 @@ enum nzAnimationType
{ {
nzAnimationType_Keyframe, nzAnimationType_Keyframe,
nzAnimationType_Skeletal, nzAnimationType_Skeletal,
nzAnimationType_Static nzAnimationType_Static,
nzAnimationType_Max = nzAnimationType_Static
}; };
enum nzBufferAccess enum nzBufferAccess
@ -19,7 +21,9 @@ enum nzBufferAccess
nzBufferAccess_DiscardAndWrite, nzBufferAccess_DiscardAndWrite,
nzBufferAccess_ReadOnly, nzBufferAccess_ReadOnly,
nzBufferAccess_ReadWrite, nzBufferAccess_ReadWrite,
nzBufferAccess_WriteOnly nzBufferAccess_WriteOnly,
nzBufferAccess_Max = nzBufferAccess_WriteOnly
}; };
enum nzBufferStorage enum nzBufferStorage
@ -34,13 +38,17 @@ enum nzBufferStorage
enum nzBufferType enum nzBufferType
{ {
nzBufferType_Index, nzBufferType_Index,
nzBufferType_Vertex nzBufferType_Vertex,
nzBufferType_Max = nzBufferType_Vertex
}; };
enum nzBufferUsage enum nzBufferUsage
{ {
nzBufferUsage_Dynamic, nzBufferUsage_Dynamic,
nzBufferUsage_Static nzBufferUsage_Static,
nzBufferUsage_Max = nzBufferUsage_Static
}; };
enum nzCubemapFace enum nzCubemapFace
@ -52,7 +60,9 @@ enum nzCubemapFace
nzCubemapFace_PositiveZ = 4, nzCubemapFace_PositiveZ = 4,
nzCubemapFace_NegativeX = 1, nzCubemapFace_NegativeX = 1,
nzCubemapFace_NegativeY = 3, nzCubemapFace_NegativeY = 3,
nzCubemapFace_NegativeZ = 5 nzCubemapFace_NegativeZ = 5,
nzCubemapFace_Max = nzCubemapFace_NegativeZ
}; };
enum nzElementStream enum nzElementStream
@ -73,7 +83,9 @@ enum nzElementType
nzElementType_Float1, nzElementType_Float1,
nzElementType_Float2, nzElementType_Float2,
nzElementType_Float3, nzElementType_Float3,
nzElementType_Float4 nzElementType_Float4,
nzElementType_Max = nzElementType_Float4
}; };
enum nzElementUsage enum nzElementUsage
@ -103,14 +115,18 @@ enum nzEventType
nzEventType_Moved, nzEventType_Moved,
nzEventType_Quit, nzEventType_Quit,
nzEventType_Resized, nzEventType_Resized,
nzEventType_TextEntered nzEventType_TextEntered,
nzEventType_Max = nzEventType_TextEntered
}; };
enum nzExtend enum nzExtend
{ {
nzExtend_Finite, nzExtend_Finite,
nzExtend_Infinite, nzExtend_Infinite,
nzExtend_Null nzExtend_Null,
nzExtend_Max = nzExtend_Null
}; };
enum nzImageType enum nzImageType
@ -150,7 +166,6 @@ enum nzPixelFormat
nzPixelFormat_RGB5A1, // 1*nzUInt16 nzPixelFormat_RGB5A1, // 1*nzUInt16
nzPixelFormat_RGB8, // 3*nzUInt8 nzPixelFormat_RGB8, // 3*nzUInt8
nzPixelFormat_RGBA8, // 4*nzUInt8 nzPixelFormat_RGBA8, // 4*nzUInt8
/*
nzPixelFormat_Depth16, nzPixelFormat_Depth16,
nzPixelFormat_Depth24, nzPixelFormat_Depth24,
nzPixelFormat_Depth24Stencil8, nzPixelFormat_Depth24Stencil8,
@ -159,9 +174,20 @@ enum nzPixelFormat
nzPixelFormat_Stencil4, nzPixelFormat_Stencil4,
nzPixelFormat_Stencil8, nzPixelFormat_Stencil8,
nzPixelFormat_Stencil16, nzPixelFormat_Stencil16,
*/
nzPixelFormat_Max = nzPixelFormat_RGBA8 nzPixelFormat_Max = nzPixelFormat_Stencil16
};
enum nzPixelFormatType
{
nzPixelFormatType_Undefined = -1,
nzPixelFormatType_Color,
nzPixelFormatType_Depth,
nzPixelFormatType_DepthStencil,
nzPixelFormatType_Stencil,
nzPixelFormatType_Max = nzPixelFormatType_Stencil
}; };
enum nzPixelFlipping enum nzPixelFlipping
@ -179,7 +205,9 @@ enum nzPrimitiveType
nzPrimitiveType_PointList, nzPrimitiveType_PointList,
nzPrimitiveType_TriangleList, nzPrimitiveType_TriangleList,
nzPrimitiveType_TriangleStrip, nzPrimitiveType_TriangleStrip,
nzPrimitiveType_TriangleFan nzPrimitiveType_TriangleFan,
nzPrimitiveType_Max = nzPrimitiveType_TriangleFan
}; };
enum nzWindowCursor enum nzWindowCursor
@ -202,10 +230,12 @@ enum nzWindowCursor
nzWindowCursor_ResizeSW, nzWindowCursor_ResizeSW,
nzWindowCursor_ResizeW, nzWindowCursor_ResizeW,
nzWindowCursor_Text, nzWindowCursor_Text,
nzWindowCursor_Wait nzWindowCursor_Wait,
nzWindowCursor_Max = nzWindowCursor_Wait
}; };
enum nzWindowStyle enum nzWindowStyleFlags
{ {
nzWindowStyle_None = 0x0, nzWindowStyle_None = 0x0,
nzWindowStyle_Fullscreen = 0x1, nzWindowStyle_Fullscreen = 0x1,

View File

@ -10,6 +10,7 @@
#include <Nazara/Prerequesites.hpp> #include <Nazara/Prerequesites.hpp>
#include <Nazara/Core/InputStream.hpp> #include <Nazara/Core/InputStream.hpp>
#include <Nazara/Core/Resource.hpp> #include <Nazara/Core/Resource.hpp>
#include <Nazara/Core/ResourceListener.hpp>
#include <Nazara/Core/ResourceLoader.hpp> #include <Nazara/Core/ResourceLoader.hpp>
#include <Nazara/Core/String.hpp> #include <Nazara/Core/String.hpp>
#include <Nazara/Utility/Animation.hpp> #include <Nazara/Utility/Animation.hpp>
@ -34,7 +35,7 @@ using NzMeshLoader = NzResourceLoader<NzMesh, NzMeshParams>;
struct NzMeshImpl; struct NzMeshImpl;
class NAZARA_API NzMesh : public NzResource class NAZARA_API NzMesh : public NzResource, NzResourceListener
{ {
friend NzMeshLoader; friend NzMeshLoader;
@ -42,9 +43,9 @@ class NAZARA_API NzMesh : public NzResource
NzMesh() = default; NzMesh() = default;
~NzMesh(); ~NzMesh();
unsigned int AddSkin(const NzString& skin, bool setDefault = false); bool AddSkin(const NzString& skin, bool setDefault = false);
nzUInt8 AddSubMesh(NzSubMesh* subMesh); bool AddSubMesh(NzSubMesh* subMesh);
nzUInt8 AddSubMesh(const NzString& identifier, NzSubMesh* subMesh); bool AddSubMesh(const NzString& identifier, NzSubMesh* subMesh);
void Animate(unsigned int frameA, unsigned int frameB, float interpolation); void Animate(unsigned int frameA, unsigned int frameB, float interpolation);
@ -58,16 +59,17 @@ class NAZARA_API NzMesh : public NzResource
NzString GetSkin(unsigned int index = 0) const; NzString GetSkin(unsigned int index = 0) const;
unsigned int GetSkinCount() const; unsigned int GetSkinCount() const;
NzSubMesh* GetSubMesh(const NzString& identifier); NzSubMesh* GetSubMesh(const NzString& identifier);
NzSubMesh* GetSubMesh(nzUInt8 index); NzSubMesh* GetSubMesh(unsigned int index);
const NzSubMesh* GetSubMesh(const NzString& identifier) const; const NzSubMesh* GetSubMesh(const NzString& identifier) const;
const NzSubMesh* GetSubMesh(nzUInt8 index) const; const NzSubMesh* GetSubMesh(unsigned int index) const;
nzUInt8 GetSubMeshCount() const; unsigned int GetSubMeshCount() const;
int GetSubMeshIndex(const NzString& identifier) const;
unsigned int GetVertexCount() const; unsigned int GetVertexCount() const;
bool HasAnimation() const; bool HasAnimation() const;
bool HasSkin(unsigned int index = 0) const; bool HasSkin(unsigned int index = 0) const;
bool HasSubMesh(const NzString& identifier) const; bool HasSubMesh(const NzString& identifier) const;
bool HasSubMesh(nzUInt8 index = 0) const; bool HasSubMesh(unsigned int index = 0) const;
void InvalidateAABB() const; void InvalidateAABB() const;
@ -80,11 +82,14 @@ class NAZARA_API NzMesh : public NzResource
void RemoveSkin(unsigned int index = 0); void RemoveSkin(unsigned int index = 0);
void RemoveSubMesh(const NzString& identifier); void RemoveSubMesh(const NzString& identifier);
void RemoveSubMesh(nzUInt8 index = 0); void RemoveSubMesh(unsigned int index = 0);
bool SetAnimation(const NzAnimation* animation); bool SetAnimation(const NzAnimation* animation);
private: private:
void OnResourceCreated(const NzResource* resource, int index) override;
void OnResourceReleased(const NzResource* resource, int index) override;
NzMeshImpl* m_impl = nullptr; NzMeshImpl* m_impl = nullptr;
static NzMeshLoader::LoaderList s_loaders; static NzMeshLoader::LoaderList s_loaders;

View File

@ -28,6 +28,7 @@ class NzPixelFormat
static bool Flip(nzPixelFlipping flipping, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth, const void* src, void* dst); static bool Flip(nzPixelFlipping flipping, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth, const void* src, void* dst);
static nzUInt8 GetBPP(nzPixelFormat format); static nzUInt8 GetBPP(nzPixelFormat format);
static nzPixelFormatType GetType(nzPixelFormat format);
static bool HasAlpha(nzPixelFormat format); static bool HasAlpha(nzPixelFormat format);

View File

@ -225,14 +225,77 @@ inline nzUInt8 NzPixelFormat::GetBPP(nzPixelFormat format)
case nzPixelFormat_RGBA8: case nzPixelFormat_RGBA8:
return 4; return 4;
case nzPixelFormat_Depth16:
return 2;
case nzPixelFormat_Depth24:
return 3;
case nzPixelFormat_Depth24Stencil8:
return 4;
case nzPixelFormat_Depth32:
return 4;
case nzPixelFormat_Stencil1:
NazaraWarning("This format uses less than one byte per pixel");
return 0;
case nzPixelFormat_Stencil4:
NazaraWarning("This format uses less than one byte per pixel");
return 0;
case nzPixelFormat_Stencil8:
return 1;
case nzPixelFormat_Stencil16:
return 2;
case nzPixelFormat_Undefined: case nzPixelFormat_Undefined:
break;
}
NazaraError("Invalid pixel format"); NazaraError("Invalid pixel format");
return 0; return 0;
} }
NazaraInternalError("Invalid pixel format"); inline nzPixelFormatType NzPixelFormat::GetType(nzPixelFormat format)
{
switch (format)
{
case nzPixelFormat_BGR8:
case nzPixelFormat_BGRA8:
case nzPixelFormat_DXT1:
case nzPixelFormat_DXT3:
case nzPixelFormat_DXT5:
case nzPixelFormat_L8:
case nzPixelFormat_LA8:
case nzPixelFormat_RGB5A1:
case nzPixelFormat_RGB8:
case nzPixelFormat_RGBA4:
case nzPixelFormat_RGBA8:
return nzPixelFormatType_Color;
return 0; case nzPixelFormat_Depth16:
case nzPixelFormat_Depth24:
case nzPixelFormat_Depth32:
return nzPixelFormatType_Depth;
case nzPixelFormat_Depth24Stencil8:
return nzPixelFormatType_DepthStencil;
case nzPixelFormat_Stencil1:
case nzPixelFormat_Stencil4:
case nzPixelFormat_Stencil8:
case nzPixelFormat_Stencil16:
return nzPixelFormatType_Stencil;
case nzPixelFormat_Undefined:
break;
}
NazaraError("Invalid pixel format");
return nzPixelFormatType_Undefined;
} }
inline bool NzPixelFormat::HasAlpha(nzPixelFormat format) inline bool NzPixelFormat::HasAlpha(nzPixelFormat format)
@ -252,6 +315,14 @@ inline bool NzPixelFormat::HasAlpha(nzPixelFormat format)
case nzPixelFormat_DXT1: case nzPixelFormat_DXT1:
case nzPixelFormat_L8: case nzPixelFormat_L8:
case nzPixelFormat_RGB8: case nzPixelFormat_RGB8:
case nzPixelFormat_Depth16:
case nzPixelFormat_Depth24:
case nzPixelFormat_Depth24Stencil8:
case nzPixelFormat_Depth32:
case nzPixelFormat_Stencil1:
case nzPixelFormat_Stencil4:
case nzPixelFormat_Stencil8:
case nzPixelFormat_Stencil16:
return false; return false;
case nzPixelFormat_Undefined: case nzPixelFormat_Undefined:
@ -271,9 +342,30 @@ inline bool NzPixelFormat::IsCompressed(nzPixelFormat format)
case nzPixelFormat_DXT5: case nzPixelFormat_DXT5:
return true; return true;
default: case nzPixelFormat_BGRA8:
case nzPixelFormat_LA8:
case nzPixelFormat_RGB5A1:
case nzPixelFormat_RGBA4:
case nzPixelFormat_RGBA8:
case nzPixelFormat_BGR8:
case nzPixelFormat_L8:
case nzPixelFormat_RGB8:
case nzPixelFormat_Depth16:
case nzPixelFormat_Depth24:
case nzPixelFormat_Depth24Stencil8:
case nzPixelFormat_Depth32:
case nzPixelFormat_Stencil1:
case nzPixelFormat_Stencil4:
case nzPixelFormat_Stencil8:
case nzPixelFormat_Stencil16:
return false; return false;
case nzPixelFormat_Undefined:
break;
} }
NazaraError("Invalid pixel format");
return false;
} }
inline bool NzPixelFormat::IsConversionSupported(nzPixelFormat srcFormat, nzPixelFormat dstFormat) inline bool NzPixelFormat::IsConversionSupported(nzPixelFormat srcFormat, nzPixelFormat dstFormat)
@ -360,6 +452,30 @@ inline NzString NzPixelFormat::ToString(nzPixelFormat format)
case nzPixelFormat_RGBA8: case nzPixelFormat_RGBA8:
return "RGBA8"; return "RGBA8";
case nzPixelFormat_Depth16:
return "Depth16";
case nzPixelFormat_Depth24:
return "Depth24";
case nzPixelFormat_Depth24Stencil8:
return "Depth24Stencil8";
case nzPixelFormat_Depth32:
return "Depth32";
case nzPixelFormat_Stencil1:
return "Stencil1";
case nzPixelFormat_Stencil4:
return "Stencil4";
case nzPixelFormat_Stencil8:
return "Stencil8";
case nzPixelFormat_Stencil16:
return "Stencil16";
case nzPixelFormat_Undefined: case nzPixelFormat_Undefined:
return "Undefined"; return "Undefined";
} }

View File

@ -8,9 +8,10 @@
#define NAZARA_STATICMESH_HPP #define NAZARA_STATICMESH_HPP
#include <Nazara/Prerequesites.hpp> #include <Nazara/Prerequesites.hpp>
#include <Nazara/Core/ResourceListener.hpp>
#include <Nazara/Utility/SubMesh.hpp> #include <Nazara/Utility/SubMesh.hpp>
class NAZARA_API NzStaticMesh final : public NzSubMesh class NAZARA_API NzStaticMesh final : public NzSubMesh, NzResourceListener
{ {
public: public:
NzStaticMesh(const NzMesh* parent); NzStaticMesh(const NzMesh* parent);
@ -38,6 +39,7 @@ class NAZARA_API NzStaticMesh final : public NzSubMesh
private: private:
void AnimateImpl(unsigned int frameA, unsigned int frameB, float interpolation); void AnimateImpl(unsigned int frameA, unsigned int frameB, float interpolation);
void OnResourceReleased(const NzResource* resource, int index) override;
nzPrimitiveType m_primitiveType = nzPrimitiveType_TriangleList; nzPrimitiveType m_primitiveType = nzPrimitiveType_TriangleList;
NzAxisAlignedBox m_aabb; NzAxisAlignedBox m_aabb;

View File

@ -46,6 +46,9 @@ class NAZARA_API NzVertexDeclaration : public NzResource
NzVertexDeclaration& operator=(const NzVertexDeclaration& declaration); NzVertexDeclaration& operator=(const NzVertexDeclaration& declaration);
NzVertexDeclaration& operator=(NzVertexDeclaration&& declaration) noexcept; NzVertexDeclaration& operator=(NzVertexDeclaration&& declaration) noexcept;
static unsigned int GetElementCount(nzElementType type);
static unsigned int GetElementSize(nzElementType type);
private: private:
NzVertexDeclarationImpl* m_sharedImpl = nullptr; NzVertexDeclarationImpl* m_sharedImpl = nullptr;
}; };

View File

@ -21,8 +21,8 @@
#include <queue> #include <queue>
#if NAZARA_UTILITY_THREADED_WINDOW #if NAZARA_UTILITY_THREADED_WINDOW
#include <Nazara/Core/ConditionVariable.hpp>
#include <Nazara/Core/Mutex.hpp> #include <Nazara/Core/Mutex.hpp>
#include <Nazara/Core/ThreadCondition.hpp>
#endif #endif
class NzCursor; class NzCursor;
@ -61,6 +61,7 @@ class NAZARA_API NzWindow : NzNonCopyable
bool IsMinimized() const; bool IsMinimized() const;
bool IsOpen() const; bool IsOpen() const;
bool IsValid() const;
bool IsVisible() const; bool IsVisible() const;
bool PollEvent(NzEvent* event); bool PollEvent(NzEvent* event);
@ -85,8 +86,8 @@ class NAZARA_API NzWindow : NzNonCopyable
bool WaitEvent(NzEvent* event); bool WaitEvent(NzEvent* event);
protected: protected:
virtual void OnWindowDestroying();
virtual bool OnWindowCreated(); virtual bool OnWindowCreated();
virtual void OnWindowDestroy();
NzWindowImpl* m_impl; NzWindowImpl* m_impl;

View File

@ -50,9 +50,6 @@ bool NzSoundBuffer::Create(nzAudioFormat format, unsigned int sampleCount, unsig
{ {
Destroy(); Destroy();
if (sampleCount == 0)
return true;
#if NAZARA_AUDIO_SAFE #if NAZARA_AUDIO_SAFE
if (!IsFormatSupported(format)) if (!IsFormatSupported(format))
{ {
@ -60,6 +57,12 @@ bool NzSoundBuffer::Create(nzAudioFormat format, unsigned int sampleCount, unsig
return false; return false;
} }
if (sampleCount == 0)
{
NazaraError("Sample rate must be different from zero");
return false;
}
if (sampleRate == 0) if (sampleRate == 0)
{ {
NazaraError("Sample rate must be different from zero"); NazaraError("Sample rate must be different from zero");
@ -104,6 +107,7 @@ bool NzSoundBuffer::Create(nzAudioFormat format, unsigned int sampleCount, unsig
m_impl->samples = new nzInt16[sampleCount]; m_impl->samples = new nzInt16[sampleCount];
std::memcpy(&m_impl->samples[0], samples, sampleCount*sizeof(nzInt16)); std::memcpy(&m_impl->samples[0], samples, sampleCount*sizeof(nzInt16));
NotifyCreated();
return true; return true;
} }
@ -111,6 +115,8 @@ void NzSoundBuffer::Destroy()
{ {
if (m_impl) if (m_impl)
{ {
NotifyDestroy();
delete[] m_impl->samples; delete[] m_impl->samples;
delete m_impl; delete m_impl;
m_impl = nullptr; m_impl = nullptr;

View File

@ -1,8 +1,8 @@
/*
// Copyright (C) 2012 Jérôme Leclercq // Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module" // This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
/*
#include <Nazara/Core/ByteArray.hpp> #include <Nazara/Core/ByteArray.hpp>
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
@ -61,7 +61,7 @@ m_sharedArray(buffer.m_sharedArray)
} }
} }
NzByteArray::NzByteArray(NzByteArray&& buffer) : NzByteArray::NzByteArray(NzByteArray&& buffer) noexcept :
m_sharedArray(buffer.m_sharedArray) m_sharedArray(buffer.m_sharedArray)
{ {
buffer.m_sharedArray = &emptyArray; buffer.m_sharedArray = &emptyArray;

View File

@ -1,4 +1,4 @@
// Copyright (C) 2012 Jérôme Leclercq // Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module" // This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
@ -73,7 +73,14 @@ void* NzMemoryManager::Allocate(std::size_t size, bool multi, const char* file,
Block* ptr = reinterpret_cast<Block*>(std::malloc(size+sizeof(Block))); Block* ptr = reinterpret_cast<Block*>(std::malloc(size+sizeof(Block)));
if (!ptr) if (!ptr)
return nullptr; // Impossible d'envoyer une exception car cela allouerait de la mémoire avec new (boucle infinie) {
// Pas d'information de temps (Car nécessitant une allocation)
FILE* log = std::fopen(MLTFileName, "a");
std::fprintf(log, "Failed to allocate memory (%d bytes)\n", size);
std::fclose(log);
return nullptr; // Impossible d'envoyer une exception car cela allouerait de la mémoire avec new (boucle infinie)
}
ptr->array = multi; ptr->array = multi;
ptr->file = file; ptr->file = file;

View File

@ -5,6 +5,7 @@
#include <Nazara/Core/Resource.hpp> #include <Nazara/Core/Resource.hpp>
#include <Nazara/Core/Config.hpp> #include <Nazara/Core/Config.hpp>
#include <Nazara/Core/Error.hpp> #include <Nazara/Core/Error.hpp>
#include <Nazara/Core/ResourceListener.hpp>
#include <Nazara/Core/Debug.hpp> #include <Nazara/Core/Debug.hpp>
NzResource::NzResource(bool persistent) : NzResource::NzResource(bool persistent) :
@ -19,20 +20,57 @@ m_resourceReferenceCount(0)
{ {
} }
NzResource::~NzResource() = default; NzResource::~NzResource()
{
EnsureResourceListenerUpdate();
for (auto it = m_resourceListenersCache.begin(); it != m_resourceListenersCache.end(); ++it)
(*it).listener->OnResourceReleased(this, (*it).index);
}
void NzResource::AddResourceListener(NzResourceListener* listener, int index) const
{
NazaraLock(m_mutex)
if (m_resourceListeners.insert(NzResourceEntry(listener, index)).second)
{
m_resourceListenerUpdated = false;
// AddResourceReference()
m_resourceReferenceCount++;
}
}
void NzResource::AddResourceReference() const void NzResource::AddResourceReference() const
{ {
NazaraLock(m_mutex)
m_resourceReferenceCount++; m_resourceReferenceCount++;
} }
bool NzResource::IsPersistent() const bool NzResource::IsPersistent() const
{ {
NazaraLock(m_mutex)
return m_resourcePersistent; return m_resourcePersistent;
} }
void NzResource::RemoveResourceListener(NzResourceListener* listener) const
{
NazaraLock(m_mutex)
if (m_resourceListeners.erase(listener) != 0)
m_resourceListenerUpdated = false;
else
NazaraError(NzString::Pointer(listener) + " is not listening to " + NzString::Pointer(this));
RemoveResourceReference();
}
void NzResource::RemoveResourceReference() const void NzResource::RemoveResourceReference() const
{ {
NazaraMutexLock(m_mutex);
#if NAZARA_CORE_SAFE #if NAZARA_CORE_SAFE
if (m_resourceReferenceCount == 0) if (m_resourceReferenceCount == 0)
{ {
@ -42,13 +80,59 @@ void NzResource::RemoveResourceReference() const
#endif #endif
if (--m_resourceReferenceCount == 0 && !m_resourcePersistent) if (--m_resourceReferenceCount == 0 && !m_resourcePersistent)
{
NazaraMutexUnlock(m_mutex);
delete this; delete this;
} }
else
{
NazaraMutexUnlock(m_mutex);
}
}
void NzResource::SetPersistent(bool persistent) void NzResource::SetPersistent(bool persistent)
{ {
NazaraMutexLock(m_mutex);
m_resourcePersistent = persistent; m_resourcePersistent = persistent;
if (!persistent && m_resourceReferenceCount == 0) if (!persistent && m_resourceReferenceCount == 0)
{
NazaraMutexUnlock(m_mutex);
delete this; delete this;
} }
else
{
NazaraMutexUnlock(m_mutex);
}
}
void NzResource::NotifyCreated()
{
NazaraLock(m_mutex)
EnsureResourceListenerUpdate();
for (auto it = m_resourceListenersCache.begin(); it != m_resourceListenersCache.end(); ++it)
(*it).listener->OnResourceCreated(this, (*it).index);
}
void NzResource::NotifyDestroy()
{
NazaraLock(m_mutex)
EnsureResourceListenerUpdate();
for (auto it = m_resourceListenersCache.begin(); it != m_resourceListenersCache.end(); ++it)
(*it).listener->OnResourceDestroy(this, (*it).index);
}
void NzResource::EnsureResourceListenerUpdate() const
{
// Déjà bloqué par une mutex
if (!m_resourceListenerUpdated)
{
m_resourceListenersCache = m_resourceListeners;
m_resourceListenerUpdated = true;
}
}

View File

@ -0,0 +1,26 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/ResourceListener.hpp>
#include <Nazara/Core/Debug.hpp>
NzResourceListener::~NzResourceListener() = default;
void NzResourceListener::OnResourceCreated(const NzResource* resource, int index)
{
NazaraUnused(resource);
NazaraUnused(index);
}
void NzResourceListener::OnResourceDestroy(const NzResource* resource, int index)
{
NazaraUnused(resource);
NazaraUnused(index);
}
void NzResourceListener::OnResourceReleased(const NzResource* resource, int index)
{
NazaraUnused(resource);
NazaraUnused(index);
}

View File

@ -11,6 +11,7 @@
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <limits>
#include <sstream> #include <sstream>
#include <Utfcpp/utf8.h> #include <Utfcpp/utf8.h>
#include <Nazara/Core/Debug.hpp> #include <Nazara/Core/Debug.hpp>
@ -108,7 +109,7 @@ NzString::NzString(const char* string)
m_sharedString->capacity = size; m_sharedString->capacity = size;
m_sharedString->size = size; m_sharedString->size = size;
m_sharedString->string = new char[size+1]; m_sharedString->string = new char[size+1];
std::strcpy(m_sharedString->string, string); std::memcpy(m_sharedString->string, string, size+1);
} }
else else
m_sharedString = &emptyString; m_sharedString = &emptyString;
@ -125,7 +126,7 @@ NzString::NzString(const std::string& string)
m_sharedString->capacity = string.capacity(); m_sharedString->capacity = string.capacity();
m_sharedString->size = string.size(); m_sharedString->size = string.size();
m_sharedString->string = new char[string.capacity()+1]; m_sharedString->string = new char[string.capacity()+1];
std::strcpy(m_sharedString->string, string.c_str()); std::memcpy(m_sharedString->string, string.c_str(), string.size()+1);
} }
else else
m_sharedString = &emptyString; m_sharedString = &emptyString;
@ -180,7 +181,7 @@ NzString& NzString::Append(char character)
unsigned int bufferSize = nzGetNewSize(newSize); unsigned int bufferSize = nzGetNewSize(newSize);
char* str = new char[bufferSize+1]; char* str = new char[bufferSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size*sizeof(char)); std::memcpy(str, m_sharedString->string, m_sharedString->size);
str[m_sharedString->size] = character; str[m_sharedString->size] = character;
str[newSize] = '\0'; str[newSize] = '\0';
@ -207,7 +208,7 @@ NzString& NzString::Append(const char* string)
{ {
EnsureOwnership(); EnsureOwnership();
std::strcpy(&m_sharedString->string[m_sharedString->size], string); std::memcpy(&m_sharedString->string[m_sharedString->size], string, length+1);
m_sharedString->size += length; m_sharedString->size += length;
} }
else else
@ -216,8 +217,8 @@ NzString& NzString::Append(const char* string)
unsigned int bufferSize = nzGetNewSize(newSize); unsigned int bufferSize = nzGetNewSize(newSize);
char* str = new char[bufferSize+1]; char* str = new char[bufferSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size*sizeof(char)); std::memcpy(str, m_sharedString->string, m_sharedString->size);
std::strcpy(&str[m_sharedString->size], string); std::memcpy(&str[m_sharedString->size], string, length+1);
ReleaseString(); ReleaseString();
m_sharedString = new SharedString; m_sharedString = new SharedString;
@ -241,7 +242,7 @@ NzString& NzString::Append(const NzString& string)
{ {
EnsureOwnership(); EnsureOwnership();
std::strcpy(&m_sharedString->string[m_sharedString->size], string.m_sharedString->string); std::memcpy(&m_sharedString->string[m_sharedString->size], string.m_sharedString->string, string.m_sharedString->size+1);
m_sharedString->size += string.m_sharedString->size; m_sharedString->size += string.m_sharedString->size;
} }
else else
@ -250,8 +251,8 @@ NzString& NzString::Append(const NzString& string)
unsigned int bufferSize = nzGetNewSize(newSize); unsigned int bufferSize = nzGetNewSize(newSize);
char* str = new char[bufferSize+1]; char* str = new char[bufferSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size*sizeof(char)); std::memcpy(str, m_sharedString->string, m_sharedString->size);
std::strcpy(&str[m_sharedString->size], string.m_sharedString->string); std::memcpy(&str[m_sharedString->size], string.m_sharedString->string, string.m_sharedString->size+1);
ReleaseString(); ReleaseString();
m_sharedString = new SharedString; m_sharedString = new SharedString;
@ -2270,7 +2271,7 @@ char* NzString::GetUtf8Buffer(unsigned int* size) const
return nullptr; return nullptr;
char* buffer = new char[m_sharedString->size+1]; char* buffer = new char[m_sharedString->size+1];
std::strcpy(buffer, m_sharedString->string); std::memcpy(buffer, m_sharedString->string, m_sharedString->size+1);
if (size) if (size)
*size = m_sharedString->size; *size = m_sharedString->size;
@ -2372,7 +2373,7 @@ wchar_t* NzString::GetWideBuffer(unsigned int* size) const
if (cp <= 0xFFFF && (cp < 0xD800 || cp > 0xDFFF)) // @Laurent Gomila if (cp <= 0xFFFF && (cp < 0xD800 || cp > 0xDFFF)) // @Laurent Gomila
*ptr++ = static_cast<wchar_t>(cp); *ptr++ = static_cast<wchar_t>(cp);
else else
*ptr++ = static_cast<wchar_t>('?'); *ptr++ = L'?';
} }
while (*it++); while (*it++);
} }
@ -2480,7 +2481,7 @@ NzString& NzString::Insert(int pos, char character)
{ {
EnsureOwnership(); EnsureOwnership();
std::memmove(&m_sharedString->string[start+1], &m_sharedString->string[start], m_sharedString->size*sizeof(char)); std::memmove(&m_sharedString->string[start+1], &m_sharedString->string[start], m_sharedString->size);
m_sharedString->string[start] = character; m_sharedString->string[start] = character;
m_sharedString->size += 1; m_sharedString->size += 1;
@ -2526,8 +2527,8 @@ NzString& NzString::Insert(int pos, const char* string)
{ {
EnsureOwnership(); EnsureOwnership();
std::memmove(&m_sharedString->string[start+len], &m_sharedString->string[start], m_sharedString->size*sizeof(char)); std::memmove(&m_sharedString->string[start+len], &m_sharedString->string[start], m_sharedString->size);
std::memcpy(&m_sharedString->string[start], string, len*sizeof(char)); std::memcpy(&m_sharedString->string[start], string, len+1);
m_sharedString->size += len; m_sharedString->size += len;
} }
@ -2576,8 +2577,8 @@ NzString& NzString::Insert(int pos, const NzString& string)
{ {
EnsureOwnership(); EnsureOwnership();
std::memmove(&m_sharedString->string[start+string.m_sharedString->size], &m_sharedString->string[start], m_sharedString->size*sizeof(char)); std::memmove(&m_sharedString->string[start+string.m_sharedString->size], &m_sharedString->string[start], m_sharedString->size);
std::memcpy(&m_sharedString->string[start], string.m_sharedString->string, string.m_sharedString->size*sizeof(char)); std::memcpy(&m_sharedString->string[start], string.m_sharedString->string, string.m_sharedString->size+1);
m_sharedString->size += string.m_sharedString->size; m_sharedString->size += string.m_sharedString->size;
} }
@ -2837,7 +2838,7 @@ unsigned int NzString::Replace(const char* oldString, const char* replaceString,
found = true; found = true;
} }
std::memcpy(&m_sharedString->string[pos], replaceString, oSize*sizeof(char)); std::memcpy(&m_sharedString->string[pos], replaceString, oSize);
pos += oSize; pos += oSize;
++count; ++count;
@ -2859,9 +2860,9 @@ unsigned int NzString::Replace(const char* oldString, const char* replaceString,
{ {
const char* r = &m_sharedString->string[pos]; const char* r = &m_sharedString->string[pos];
std::memcpy(ptr, p, (r-p)*sizeof(char)); std::memcpy(ptr, p, r-p);
ptr += r-p; ptr += r-p;
std::memcpy(ptr, replaceString, rSize*sizeof(char)); std::memcpy(ptr, replaceString, rSize);
ptr += rSize; ptr += rSize;
p = r+oSize; p = r+oSize;
pos += oSize; pos += oSize;
@ -2907,7 +2908,7 @@ unsigned int NzString::Replace(const NzString& oldString, const NzString& replac
found = true; found = true;
} }
std::memcpy(&m_sharedString->string[pos], replaceString.m_sharedString->string, oldString.m_sharedString->size*sizeof(char)); std::memcpy(&m_sharedString->string[pos], replaceString.m_sharedString->string, oldString.m_sharedString->size);
pos += oldString.m_sharedString->size; pos += oldString.m_sharedString->size;
++count; ++count;
@ -2929,9 +2930,9 @@ unsigned int NzString::Replace(const NzString& oldString, const NzString& replac
{ {
const char* r = &m_sharedString->string[pos]; const char* r = &m_sharedString->string[pos];
std::memcpy(ptr, p, (r-p)*sizeof(char)); std::memcpy(ptr, p, r-p);
ptr += r-p; ptr += r-p;
std::memcpy(ptr, replaceString.m_sharedString->string, replaceString.m_sharedString->size*sizeof(char)); std::memcpy(ptr, replaceString.m_sharedString->string, replaceString.m_sharedString->size);
ptr += replaceString.m_sharedString->size; ptr += replaceString.m_sharedString->size;
p = r+oldString.m_sharedString->size; p = r+oldString.m_sharedString->size;
pos += oldString.m_sharedString->size; pos += oldString.m_sharedString->size;
@ -3189,7 +3190,7 @@ void NzString::Reserve(unsigned int bufferSize)
char* ptr = new char[bufferSize+1]; char* ptr = new char[bufferSize+1];
if (m_sharedString->size > 0) if (m_sharedString->size > 0)
std::strcpy(ptr, m_sharedString->string); std::memcpy(ptr, m_sharedString->string, m_sharedString->size+1);
unsigned int size = m_sharedString->size; unsigned int size = m_sharedString->size;
@ -3233,7 +3234,7 @@ NzString& NzString::Resize(int size, char character)
{ {
char* newString = new char[newSize+1]; char* newString = new char[newSize+1];
if (m_sharedString->size != 0) if (m_sharedString->size != 0)
std::memcpy(newString, m_sharedString->string, newSize*sizeof(char)); std::memcpy(newString, m_sharedString->string, newSize);
char* ptr = &newString[m_sharedString->size]; char* ptr = &newString[m_sharedString->size];
char* limit = &newString[newSize]; char* limit = &newString[newSize];
@ -3673,7 +3674,7 @@ bool NzString::StartsWith(const NzString& string, nzUInt32 flags) const
} }
} }
else else
return std::memcmp(m_sharedString->string, string.m_sharedString->string, string.m_sharedString->size*sizeof(char)) == 0; return std::memcmp(m_sharedString->string, string.m_sharedString->string, string.m_sharedString->size) == 0;
return false; return false;
} }
@ -3699,7 +3700,7 @@ NzString NzString::Substr(int startPos, int endPos) const
unsigned int size = minEnd-start+1; unsigned int size = minEnd-start+1;
char* str = new char[size+1]; char* str = new char[size+1];
std::memcpy(str, &m_sharedString->string[start], size*sizeof(char)); std::memcpy(str, &m_sharedString->string[start], size);
str[size] = '\0'; str[size] = '\0';
return NzString(new SharedString(1, size, size, str)); return NzString(new SharedString(1, size, size, str));
@ -4185,7 +4186,7 @@ NzString& NzString::operator=(const char* string)
} }
m_sharedString->size = size; m_sharedString->size = size;
std::strcpy(m_sharedString->string, string); std::memcpy(m_sharedString->string, string, size+1);
} }
else else
ReleaseString(); ReleaseString();
@ -4209,7 +4210,7 @@ NzString& NzString::operator=(const std::string& string)
} }
m_sharedString->size = string.size(); m_sharedString->size = string.size();
std::strcpy(m_sharedString->string, string.c_str()); std::memcpy(m_sharedString->string, string.c_str(), string.size()+1);
} }
else else
ReleaseString(); ReleaseString();
@ -4246,7 +4247,7 @@ NzString NzString::operator+(char character) const
unsigned int totalSize = m_sharedString->size+1; unsigned int totalSize = m_sharedString->size+1;
char* str = new char[totalSize+1]; char* str = new char[totalSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size*sizeof(char)); std::memcpy(str, m_sharedString->string, m_sharedString->size);
str[m_sharedString->size] = character; str[m_sharedString->size] = character;
str[totalSize] = '\0'; str[totalSize] = '\0';
@ -4268,8 +4269,8 @@ NzString NzString::operator+(const char* string) const
unsigned int totalSize = m_sharedString->size + length; unsigned int totalSize = m_sharedString->size + length;
char* str = new char[totalSize+1]; char* str = new char[totalSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size*sizeof(char)); std::memcpy(str, m_sharedString->string, m_sharedString->size);
std::strcpy(&str[m_sharedString->size], string); std::memcpy(&str[m_sharedString->size], string, length+1);
return NzString(new SharedString(1, totalSize, totalSize, str)); return NzString(new SharedString(1, totalSize, totalSize, str));
} }
@ -4284,8 +4285,8 @@ NzString NzString::operator+(const std::string& string) const
unsigned int totalSize = m_sharedString->size + string.size(); unsigned int totalSize = m_sharedString->size + string.size();
char* str = new char[totalSize+1]; char* str = new char[totalSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size*sizeof(char)); std::memcpy(str, m_sharedString->string, m_sharedString->size);
std::strcpy(&str[m_sharedString->size], string.c_str()); std::memcpy(&str[m_sharedString->size], string.c_str(), string.size()+1);
return NzString(new SharedString(1, totalSize, totalSize, str)); return NzString(new SharedString(1, totalSize, totalSize, str));
} }
@ -4300,8 +4301,8 @@ NzString NzString::operator+(const NzString& string) const
unsigned int totalSize = m_sharedString->size + string.m_sharedString->size; unsigned int totalSize = m_sharedString->size + string.m_sharedString->size;
char* str = new char[totalSize+1]; char* str = new char[totalSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size*sizeof(char)); std::memcpy(str, m_sharedString->string, m_sharedString->size);
std::strcpy(&str[m_sharedString->size], string.m_sharedString->string); std::memcpy(&str[m_sharedString->size], string.m_sharedString->string, string.m_sharedString->size+1);
return NzString(new SharedString(1, totalSize, totalSize, str)); return NzString(new SharedString(1, totalSize, totalSize, str));
} }
@ -4328,7 +4329,7 @@ NzString& NzString::operator+=(char character)
unsigned int bufferSize = nzGetNewSize(newSize); unsigned int bufferSize = nzGetNewSize(newSize);
char* str = new char[bufferSize+1]; char* str = new char[bufferSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size*sizeof(char)); std::memcpy(str, m_sharedString->string, m_sharedString->size);
str[m_sharedString->size] = character; str[m_sharedString->size] = character;
str[newSize] = '\0'; str[newSize] = '\0';
@ -4350,25 +4351,25 @@ NzString& NzString::operator+=(const char* string)
if (m_sharedString->size == 0) if (m_sharedString->size == 0)
return operator=(string); return operator=(string);
unsigned int length = std::strlen(string); unsigned int size = std::strlen(string);
if (length == 0) if (size == 0)
return *this; return *this;
if (m_sharedString->capacity >= m_sharedString->size + length) if (m_sharedString->capacity >= m_sharedString->size + size)
{ {
EnsureOwnership(); EnsureOwnership();
std::strcpy(&m_sharedString->string[m_sharedString->size], string); std::memcpy(&m_sharedString->string[m_sharedString->size], string, size+1);
m_sharedString->size += length; m_sharedString->size += size;
} }
else else
{ {
unsigned int newSize = m_sharedString->size + length; unsigned int newSize = m_sharedString->size + size;
unsigned int bufferSize = nzGetNewSize(newSize); unsigned int bufferSize = nzGetNewSize(newSize);
char* str = new char[bufferSize+1]; char* str = new char[bufferSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size*sizeof(char)); std::memcpy(str, m_sharedString->string, m_sharedString->size);
std::strcpy(&str[m_sharedString->size], string); std::memcpy(&str[m_sharedString->size], string, size+1);
ReleaseString(); ReleaseString();
m_sharedString = new SharedString; m_sharedString = new SharedString;
@ -4392,7 +4393,7 @@ NzString& NzString::operator+=(const std::string& string)
{ {
EnsureOwnership(); EnsureOwnership();
std::strcpy(&m_sharedString->string[m_sharedString->size], string.c_str()); std::memcpy(&m_sharedString->string[m_sharedString->size], string.c_str(), string.size()+1);
m_sharedString->size += string.size(); m_sharedString->size += string.size();
} }
else else
@ -4401,8 +4402,8 @@ NzString& NzString::operator+=(const std::string& string)
unsigned int bufferSize = nzGetNewSize(newSize); unsigned int bufferSize = nzGetNewSize(newSize);
char* str = new char[bufferSize+1]; char* str = new char[bufferSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size*sizeof(char)); std::memcpy(str, m_sharedString->string, m_sharedString->size);
std::strcpy(&str[m_sharedString->size], string.c_str()); std::memcpy(&str[m_sharedString->size], string.c_str(), string.size()+1);
ReleaseString(); ReleaseString();
m_sharedString = new SharedString; m_sharedString = new SharedString;
@ -4426,7 +4427,7 @@ NzString& NzString::operator+=(const NzString& string)
{ {
EnsureOwnership(); EnsureOwnership();
std::strcpy(&m_sharedString->string[m_sharedString->size], string.m_sharedString->string); std::memcpy(&m_sharedString->string[m_sharedString->size], string.m_sharedString->string, string.m_sharedString->size+1);
m_sharedString->size += string.m_sharedString->size; m_sharedString->size += string.m_sharedString->size;
} }
else else
@ -4435,8 +4436,8 @@ NzString& NzString::operator+=(const NzString& string)
unsigned int bufferSize = nzGetNewSize(newSize); unsigned int bufferSize = nzGetNewSize(newSize);
char* str = new char[bufferSize+1]; char* str = new char[bufferSize+1];
std::memcpy(str, m_sharedString->string, m_sharedString->size*sizeof(char)); std::memcpy(str, m_sharedString->string, m_sharedString->size);
std::strcpy(&str[m_sharedString->size], string.m_sharedString->string); std::memcpy(&str[m_sharedString->size], string.m_sharedString->string, string.m_sharedString->size+1);
ReleaseString(); ReleaseString();
m_sharedString = new SharedString; m_sharedString = new SharedString;
@ -4902,7 +4903,7 @@ NzString operator+(char character, const NzString& string)
unsigned int totalSize = string.m_sharedString->size+1; unsigned int totalSize = string.m_sharedString->size+1;
char* str = new char[totalSize+1]; char* str = new char[totalSize+1];
str[0] = character; str[0] = character;
std::strcpy(str, string.m_sharedString->string); std::memcpy(str, string.m_sharedString->string, string.m_sharedString->size+1);
return NzString(new NzString::SharedString(1, totalSize, totalSize, str)); return NzString(new NzString::SharedString(1, totalSize, totalSize, str));
} }
@ -4918,8 +4919,8 @@ NzString operator+(const char* string, const NzString& nstring)
unsigned int size = std::strlen(string); unsigned int size = std::strlen(string);
unsigned int totalSize = size + nstring.m_sharedString->size; unsigned int totalSize = size + nstring.m_sharedString->size;
char* str = new char[totalSize+1]; char* str = new char[totalSize+1];
std::memcpy(str, string, size*sizeof(char)); std::memcpy(str, string, size);
std::strcpy(&str[size], nstring.m_sharedString->string); std::memcpy(&str[size], nstring.m_sharedString->string, nstring.m_sharedString->size+1);
return NzString(new NzString::SharedString(1, totalSize, totalSize, str)); return NzString(new NzString::SharedString(1, totalSize, totalSize, str));
} }
@ -4934,8 +4935,8 @@ NzString operator+(const std::string& string, const NzString& nstring)
unsigned int totalSize = string.size() + nstring.m_sharedString->size; unsigned int totalSize = string.size() + nstring.m_sharedString->size;
char* str = new char[totalSize+1]; char* str = new char[totalSize+1];
std::memcpy(str, string.c_str(), string.size()*sizeof(char)); std::memcpy(str, string.c_str(), string.size());
std::strcpy(&str[string.size()], nstring.m_sharedString->string); std::memcpy(&str[string.size()], nstring.m_sharedString->string, nstring.m_sharedString->size+1);
return NzString(new NzString::SharedString(1, totalSize, totalSize, str)); return NzString(new NzString::SharedString(1, totalSize, totalSize, str));
} }
@ -5083,7 +5084,7 @@ void NzString::EnsureOwnership()
m_sharedString->refCount--; m_sharedString->refCount--;
char* string = new char[m_sharedString->capacity+1]; char* string = new char[m_sharedString->capacity+1];
std::strcpy(string, m_sharedString->string); std::memcpy(string, m_sharedString->string, m_sharedString->size+1);
m_sharedString = new SharedString(1, m_sharedString->capacity, m_sharedString->size, string); m_sharedString = new SharedString(1, m_sharedString->capacity, m_sharedString->size, string);
} }
@ -5115,7 +5116,7 @@ void NzString::ReleaseString()
} }
NzString::SharedString NzString::emptyString(0, 0, 0, nullptr); NzString::SharedString NzString::emptyString(0, 0, 0, nullptr);
unsigned int NzString::npos(static_cast<unsigned int>(-1)); const unsigned int NzString::npos(std::numeric_limits<unsigned int>::max());
namespace std namespace std
{ {

View File

@ -172,15 +172,17 @@ bool NzContext::Create(const NzContextParameters& parameters)
if (m_parameters.antialiasingLevel > 0) if (m_parameters.antialiasingLevel > 0)
glEnable(GL_MULTISAMPLE); glEnable(GL_MULTISAMPLE);
if (NzOpenGL::IsSupported(NzOpenGL::DebugOutput) && m_parameters.debugMode) if (NzOpenGL::IsSupported(nzOpenGLExtension_DebugOutput) && m_parameters.debugMode)
{ {
glDebugMessageCallback(&DebugCallback, this); glDebugMessageCallback(&DebugCallback, this);
#ifdef NAZARA_DEBUG #ifdef NAZARA_DEBUG
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
#endif #endif
} }
NotifyCreated();
return true; return true;
} }
@ -188,6 +190,8 @@ void NzContext::Destroy()
{ {
if (m_impl) if (m_impl)
{ {
NotifyDestroy();
if (currentContext == this) if (currentContext == this)
NzContextImpl::Desactivate(); NzContextImpl::Desactivate();

View File

@ -14,22 +14,6 @@
namespace namespace
{ {
///FIXME: Déclaré deux fois (ici et dans Renderer.cpp)
const nzUInt8 attribIndex[] =
{
2, // nzElementUsage_Diffuse
1, // nzElementUsage_Normal
0, // nzElementUsage_Position
3, // nzElementUsage_Tangent
4 // nzElementUsage_TexCoord
};
const GLenum shaderType[nzShaderType_Max+1] = {
GL_FRAGMENT_SHADER, // nzShaderType_Fragment
GL_GEOMETRY_SHADER, // nzShaderType_Geometry
GL_VERTEX_SHADER // nzShaderType_Vertex
};
GLuint lockedPrevious = 0; GLuint lockedPrevious = 0;
nzUInt8 lockedLevel = 0; nzUInt8 lockedLevel = 0;
} }
@ -41,6 +25,8 @@ m_parent(parent)
NzGLSLShader::~NzGLSLShader() NzGLSLShader::~NzGLSLShader()
{ {
for (auto it = m_textures.begin(); it != m_textures.end(); ++it)
it->second.texture->RemoveResourceListener(this);
} }
bool NzGLSLShader::Bind() bool NzGLSLShader::Bind()
@ -71,11 +57,11 @@ bool NzGLSLShader::BindTextures()
for (auto it = m_textures.begin(); it != m_textures.end(); ++it) for (auto it = m_textures.begin(); it != m_textures.end(); ++it)
{ {
TextureSlot& slot = it->second; TextureSlot& slot = it->second;
if (!slot.updated) if (slot.enabled && !slot.updated)
{ {
glActiveTexture(GL_TEXTURE0 + slot.unit); glActiveTexture(GL_TEXTURE0 + slot.unit);
if (!slot.texture->Bind()) if (!slot.texture->Prepare())
NazaraWarning("Failed to bind texture"); NazaraWarning("Failed to prepare texture");
slot.updated = true; slot.updated = true;
} }
@ -137,17 +123,35 @@ bool NzGLSLShader::Create()
return false; return false;
} }
glBindAttribLocation(m_program, attribIndex[nzElementUsage_Position], "Position"); glBindAttribLocation(m_program, NzOpenGL::AttributeIndex[nzElementUsage_Position], "Position");
glBindAttribLocation(m_program, attribIndex[nzElementUsage_Normal], "Normal"); glBindAttribLocation(m_program, NzOpenGL::AttributeIndex[nzElementUsage_Normal], "Normal");
glBindAttribLocation(m_program, attribIndex[nzElementUsage_Diffuse], "Diffuse"); glBindAttribLocation(m_program, NzOpenGL::AttributeIndex[nzElementUsage_Diffuse], "Diffuse");
glBindAttribLocation(m_program, attribIndex[nzElementUsage_Tangent], "Tangent"); glBindAttribLocation(m_program, NzOpenGL::AttributeIndex[nzElementUsage_Tangent], "Tangent");
NzString uniform = "TexCoord"; NzString uniform;
unsigned int maxTexCoords = NzRenderer::GetMaxTextureUnits();
static const unsigned int maxTexCoords = NzRenderer::GetMaxTextureUnits();
uniform.Reserve(10); // 8 + 2
uniform = "TexCoord";
for (unsigned int i = 0; i < maxTexCoords; ++i) for (unsigned int i = 0; i < maxTexCoords; ++i)
{ {
NzString uniformName = uniform + NzString::Number(i); NzString uniformName = uniform + NzString::Number(i);
glBindAttribLocation(m_program, attribIndex[nzElementUsage_TexCoord]+i, uniformName.GetConstBuffer()); glBindAttribLocation(m_program, NzOpenGL::AttributeIndex[nzElementUsage_TexCoord]+i, uniformName.GetConstBuffer());
}
static const bool mrtSupported = NzRenderer::HasCapability(nzRendererCap_MultipleRenderTargets);
if (mrtSupported)
{
static const unsigned int maxRenderTargets = NzRenderer::GetMaxRenderTargets();
uniform.Reserve(14); // 12 + 2
uniform = "RenderTarget";
for (unsigned int i = 0; i < maxRenderTargets; ++i)
{
NzString uniformName = uniform + NzString::Number(i);
glBindFragDataLocation(m_program, i, uniformName.GetConstBuffer());
}
} }
for (int i = 0; i <= nzShaderType_Max; ++i) for (int i = 0; i <= nzShaderType_Max; ++i)
@ -224,7 +228,7 @@ bool NzGLSLShader::Load(nzShaderType type, const NzString& source)
{ {
NzContext::EnsureContext(); NzContext::EnsureContext();
GLuint shader = glCreateShader(shaderType[type]); GLuint shader = glCreateShader(NzOpenGL::ShaderType[type]);
if (!shader) if (!shader)
{ {
m_log = "Failed to create shader object"; m_log = "Failed to create shader object";
@ -301,7 +305,12 @@ bool NzGLSLShader::SendBoolean(int location, bool value)
glProgramUniform1i(m_program, location, value); glProgramUniform1i(m_program, location, value);
else else
{ {
Lock(); if (!Lock())
{
NazaraError("Failed to lock shader");
return false;
}
glUniform1i(location, value); glUniform1i(location, value);
Unlock(); Unlock();
} }
@ -315,7 +324,12 @@ bool NzGLSLShader::SendDouble(int location, double value)
glProgramUniform1d(m_program, location, value); glProgramUniform1d(m_program, location, value);
else else
{ {
Lock(); if (!Lock())
{
NazaraError("Failed to lock shader");
return false;
}
glUniform1d(location, value); glUniform1d(location, value);
Unlock(); Unlock();
} }
@ -329,7 +343,12 @@ bool NzGLSLShader::SendFloat(int location, float value)
glProgramUniform1f(m_program, location, value); glProgramUniform1f(m_program, location, value);
else else
{ {
Lock(); if (!Lock())
{
NazaraError("Failed to lock shader");
return false;
}
glUniform1f(location, value); glUniform1f(location, value);
Unlock(); Unlock();
} }
@ -343,7 +362,12 @@ bool NzGLSLShader::SendInteger(int location, int value)
glProgramUniform1i(m_program, location, value); glProgramUniform1i(m_program, location, value);
else else
{ {
Lock(); if (!Lock())
{
NazaraError("Failed to lock shader");
return false;
}
glUniform1i(location, value); glUniform1i(location, value);
Unlock(); Unlock();
} }
@ -357,7 +381,12 @@ bool NzGLSLShader::SendMatrix(int location, const NzMatrix4d& matrix)
glProgramUniformMatrix4dv(m_program, location, 1, GL_FALSE, matrix); glProgramUniformMatrix4dv(m_program, location, 1, GL_FALSE, matrix);
else else
{ {
Lock(); if (!Lock())
{
NazaraError("Failed to lock shader");
return false;
}
glUniformMatrix4dv(location, 1, GL_FALSE, matrix); glUniformMatrix4dv(location, 1, GL_FALSE, matrix);
Unlock(); Unlock();
} }
@ -371,7 +400,12 @@ bool NzGLSLShader::SendMatrix(int location, const NzMatrix4f& matrix)
glProgramUniformMatrix4fv(m_program, location, 1, GL_FALSE, matrix); glProgramUniformMatrix4fv(m_program, location, 1, GL_FALSE, matrix);
else else
{ {
Lock(); if (!Lock())
{
NazaraError("Failed to lock shader");
return false;
}
glUniformMatrix4fv(location, 1, GL_FALSE, matrix); glUniformMatrix4fv(location, 1, GL_FALSE, matrix);
Unlock(); Unlock();
} }
@ -388,12 +422,12 @@ bool NzGLSLShader::SendTexture(int location, const NzTexture* texture)
TextureSlot& slot = it->second; TextureSlot& slot = it->second;
if (slot.texture != texture) if (slot.texture != texture)
{ {
slot.texture->RemoveResourceReference(); slot.texture->RemoveResourceListener(this);
if (texture) if (texture)
{ {
slot.texture = texture; slot.texture = texture;
slot.texture->AddResourceReference(); slot.texture->AddResourceListener(this, location);
slot.updated = false; slot.updated = false;
} }
@ -439,21 +473,30 @@ bool NzGLSLShader::SendTexture(int location, const NzTexture* texture)
} }
TextureSlot slot; TextureSlot slot;
slot.enabled = texture->IsValid();
slot.unit = unit; slot.unit = unit;
slot.texture = texture; slot.texture = texture;
texture->AddResourceReference(); texture->AddResourceListener(this, location);
m_textures[location] = slot; m_textures[location] = slot;
if (slot.enabled)
{
if (glProgramUniform1i) if (glProgramUniform1i)
glProgramUniform1i(m_program, location, unit); glProgramUniform1i(m_program, location, unit);
else else
{ {
Lock(); if (!Lock())
{
NazaraError("Failed to lock shader");
return false;
}
glUniform1i(location, unit); glUniform1i(location, unit);
Unlock(); Unlock();
} }
} }
}
return true; return true;
} }
@ -464,7 +507,12 @@ bool NzGLSLShader::SendVector(int location, const NzVector2d& vector)
glProgramUniform2dv(m_program, location, 1, vector); glProgramUniform2dv(m_program, location, 1, vector);
else else
{ {
Lock(); if (!Lock())
{
NazaraError("Failed to lock shader");
return false;
}
glUniform2dv(location, 1, vector); glUniform2dv(location, 1, vector);
Unlock(); Unlock();
} }
@ -478,7 +526,12 @@ bool NzGLSLShader::SendVector(int location, const NzVector2f& vector)
glProgramUniform2fv(m_program, location, 1, vector); glProgramUniform2fv(m_program, location, 1, vector);
else else
{ {
Lock(); if (!Lock())
{
NazaraError("Failed to lock shader");
return false;
}
glUniform2fv(location, 1, vector); glUniform2fv(location, 1, vector);
Unlock(); Unlock();
} }
@ -492,7 +545,12 @@ bool NzGLSLShader::SendVector(int location, const NzVector3d& vector)
glProgramUniform3dv(m_program, location, 1, vector); glProgramUniform3dv(m_program, location, 1, vector);
else else
{ {
Lock(); if (!Lock())
{
NazaraError("Failed to lock shader");
return false;
}
glUniform3dv(location, 1, vector); glUniform3dv(location, 1, vector);
Unlock(); Unlock();
} }
@ -506,7 +564,12 @@ bool NzGLSLShader::SendVector(int location, const NzVector3f& vector)
glProgramUniform3fv(m_program, location, 1, vector); glProgramUniform3fv(m_program, location, 1, vector);
else else
{ {
Lock(); if (!Lock())
{
NazaraError("Failed to lock shader");
return false;
}
glUniform3fv(location, 1, vector); glUniform3fv(location, 1, vector);
Unlock(); Unlock();
} }
@ -520,7 +583,12 @@ bool NzGLSLShader::SendVector(int location, const NzVector4d& vector)
glProgramUniform4dv(m_program, location, 1, vector); glProgramUniform4dv(m_program, location, 1, vector);
else else
{ {
Lock(); if (!Lock())
{
NazaraError("Failed to lock shader");
return false;
}
glUniform4dv(location, 1, vector); glUniform4dv(location, 1, vector);
Unlock(); Unlock();
} }
@ -534,7 +602,12 @@ bool NzGLSLShader::SendVector(int location, const NzVector4f& vector)
glProgramUniform4fv(m_program, location, 1, vector); glProgramUniform4fv(m_program, location, 1, vector);
else else
{ {
Lock(); if (!Lock())
{
NazaraError("Failed to lock shader");
return false;
}
glUniform4fv(location, 1, vector); glUniform4fv(location, 1, vector);
Unlock(); Unlock();
} }
@ -576,3 +649,64 @@ void NzGLSLShader::Unlock()
if (--lockedLevel == 0 && lockedPrevious != m_program) if (--lockedLevel == 0 && lockedPrevious != m_program)
glUseProgram(lockedPrevious); glUseProgram(lockedPrevious);
} }
void NzGLSLShader::OnResourceCreated(const NzResource* resource, int index)
{
NazaraUnused(resource);
auto it = m_textures.find(index);
#ifdef NAZARA_DEBUG
if (it == m_textures.end())
{
NazaraInternalError("Invalid index (" + NzString::Number(index) + ')');
return;
}
#endif
TextureSlot& slot = it->second;
#ifdef NAZARA_DEBUG
if (slot.texture != resource)
{
NazaraInternalError("Wrong texture at location #" + NzString::Number(index));
return;
}
#endif
slot.enabled = true;
slot.updated = false;
}
void NzGLSLShader::OnResourceDestroy(const NzResource* resource, int index)
{
NazaraUnused(resource);
auto it = m_textures.find(index);
#ifdef NAZARA_DEBUG
if (it == m_textures.end())
{
NazaraInternalError("Invalid index (" + NzString::Number(index) + ')');
return;
}
#endif
TextureSlot& slot = it->second;
#ifdef NAZARA_DEBUG
if (slot.texture != resource)
{
NazaraInternalError("Wrong texture at location #" + NzString::Number(index));
return;
}
#endif
slot.enabled = false;
}
void NzGLSLShader::OnResourceReleased(const NzResource* resource, int index)
{
if (m_textures.erase(index) == 0)
NazaraInternalError("Texture " + NzString::Pointer(resource) + " not found");
}

View File

@ -7,13 +7,16 @@
#ifndef NAZARA_GLSLSHADER_HPP #ifndef NAZARA_GLSLSHADER_HPP
#define NAZARA_GLSLSHADER_HPP #define NAZARA_GLSLSHADER_HPP
#include <Nazara/Core/ResourceListener.hpp>
#include <Nazara/Core/String.hpp> #include <Nazara/Core/String.hpp>
#include <Nazara/Renderer/OpenGL.hpp> #include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/Shader.hpp> #include <Nazara/Renderer/Shader.hpp>
#include <Nazara/Renderer/ShaderImpl.hpp> #include <Nazara/Renderer/ShaderImpl.hpp>
#include <map> #include <map>
class NzGLSLShader : public NzShaderImpl class NzResource;
class NzGLSLShader : public NzShaderImpl, NzResourceListener
{ {
public: public:
NzGLSLShader(NzShader* parent); NzGLSLShader(NzShader* parent);
@ -55,8 +58,13 @@ class NzGLSLShader : public NzShaderImpl
void Unlock(); void Unlock();
private: private:
void OnResourceCreated(const NzResource* resource, int index) override;
void OnResourceDestroy(const NzResource* resource, int index) override;
void OnResourceReleased(const NzResource* resource, int index) override;
struct TextureSlot struct TextureSlot
{ {
bool enabled;
bool updated = false; bool updated = false;
nzUInt8 unit; nzUInt8 unit;
const NzTexture* texture; const NzTexture* texture;

View File

@ -12,38 +12,6 @@
namespace namespace
{ {
GLenum bufferLock[] = {
GL_WRITE_ONLY, // nzBufferAccess_DiscardAndWrite
GL_READ_ONLY, // nzBufferAccess_ReadOnly
GL_READ_WRITE, // nzBufferAccess_ReadWrite
GL_WRITE_ONLY // nzBufferAccess_WriteOnly
};
GLenum bufferLockRange[] = {
GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_DiscardAndWrite
GL_MAP_READ_BIT, // nzBufferAccess_ReadOnly
GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_ReadWrite
GL_MAP_WRITE_BIT // nzBufferAccess_WriteOnly
};
GLenum bufferTarget[] = {
GL_ELEMENT_ARRAY_BUFFER, // nzBufferType_Index,
GL_ARRAY_BUFFER, // nzBufferType_Vertex
};
GLenum bufferTargetBinding[] = {
GL_ELEMENT_ARRAY_BUFFER_BINDING, // nzBufferType_Index,
GL_ARRAY_BUFFER_BINDING, // nzBufferType_Vertex
};
GLenum bufferUsage[] = {
// J'ai choisi DYNAMIC à la place de STREAM car DYNAMIC semble plus adapté au profil "une mise à jour pour quelques rendus"
// Ce qui est je pense le scénario qui arrivera le plus souvent (Prévoir une option pour permettre d'utiliser le STREAM_DRAW ?)
// Source: http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=160839
GL_DYNAMIC_DRAW, // nzBufferUsage_Dynamic
GL_STATIC_DRAW // nzBufferUsage_Static
};
using LockRoutine = nzUInt8* (*)(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size); using LockRoutine = nzUInt8* (*)(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size);
nzUInt8* LockBuffer(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size) nzUInt8* LockBuffer(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size)
@ -53,16 +21,16 @@ namespace
if (access == nzBufferAccess_DiscardAndWrite) if (access == nzBufferAccess_DiscardAndWrite)
{ {
GLint bufSize; GLint bufSize;
glGetBufferParameteriv(bufferTargetBinding[type], GL_BUFFER_SIZE, &bufSize); glGetBufferParameteriv(NzOpenGL::BufferTargetBinding[type], GL_BUFFER_SIZE, &bufSize);
GLint bufUsage; GLint bufUsage;
glGetBufferParameteriv(bufferTargetBinding[type], GL_BUFFER_USAGE, &bufUsage); glGetBufferParameteriv(NzOpenGL::BufferTargetBinding[type], GL_BUFFER_USAGE, &bufUsage);
// On discard le buffer // On discard le buffer
glBufferData(bufferTargetBinding[type], bufSize, nullptr, bufUsage); glBufferData(NzOpenGL::BufferTargetBinding[type], bufSize, nullptr, bufUsage);
} }
void* ptr = glMapBuffer(bufferTarget[type], bufferLock[access]); void* ptr = glMapBuffer(NzOpenGL::BufferTarget[type], NzOpenGL::BufferLock[access]);
if (ptr) if (ptr)
return reinterpret_cast<nzUInt8*>(ptr) + offset; return reinterpret_cast<nzUInt8*>(ptr) + offset;
else else
@ -71,7 +39,7 @@ namespace
nzUInt8* LockBufferRange(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size) nzUInt8* LockBufferRange(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size)
{ {
return reinterpret_cast<nzUInt8*>(glMapBufferRange(bufferTarget[type], offset, size, bufferLockRange[access])); return reinterpret_cast<nzUInt8*>(glMapBufferRange(NzOpenGL::BufferTarget[type], offset, size, NzOpenGL::BufferLockRange[access]));
} }
nzUInt8* LockBufferFirstRun(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size); nzUInt8* LockBufferFirstRun(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size);
@ -109,7 +77,7 @@ void NzHardwareBuffer::Bind()
} }
#endif #endif
glBindBuffer(bufferTarget[m_type], m_buffer); glBindBuffer(NzOpenGL::BufferTarget[m_type], m_buffer);
} }
bool NzHardwareBuffer::Create(unsigned int size, nzBufferUsage usage) bool NzHardwareBuffer::Create(unsigned int size, nzBufferUsage usage)
@ -120,14 +88,14 @@ bool NzHardwareBuffer::Create(unsigned int size, nzBufferUsage usage)
glGenBuffers(1, &m_buffer); glGenBuffers(1, &m_buffer);
GLint previous; GLint previous;
glGetIntegerv(bufferTargetBinding[m_type], &previous); glGetIntegerv(NzOpenGL::BufferTargetBinding[m_type], &previous);
glBindBuffer(bufferTarget[m_type], m_buffer); glBindBuffer(NzOpenGL::BufferTarget[m_type], m_buffer);
glBufferData(bufferTarget[m_type], size, nullptr, bufferUsage[usage]); glBufferData(NzOpenGL::BufferTarget[m_type], size, nullptr, NzOpenGL::BufferUsage[usage]);
// Pour ne pas perturber le rendu, on interfère pas avec le binding déjà présent // Pour ne pas perturber le rendu, on interfère pas avec le binding déjà présent
if (previous != 0) if (previous != 0)
glBindBuffer(bufferTarget[m_type], previous); glBindBuffer(NzOpenGL::BufferTarget[m_type], previous);
return true; return true;
} }
@ -144,10 +112,10 @@ bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int
NzContext::EnsureContext(); NzContext::EnsureContext();
GLuint previous; GLuint previous;
glGetIntegerv(bufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous)); glGetIntegerv(NzOpenGL::BufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous));
if (previous != m_buffer) if (previous != m_buffer)
glBindBuffer(bufferTarget[m_type], m_buffer); glBindBuffer(NzOpenGL::BufferTarget[m_type], m_buffer);
// Il semblerait que glBuffer(Sub)Data soit plus performant que glMapBuffer(Range) en dessous d'un certain seuil // Il semblerait que glBuffer(Sub)Data soit plus performant que glMapBuffer(Range) en dessous d'un certain seuil
// http://www.stevestreeting.com/2007/03/17/glmapbuffer-vs-glbuffersubdata-the-return/ // http://www.stevestreeting.com/2007/03/17/glmapbuffer-vs-glbuffersubdata-the-return/
@ -155,9 +123,9 @@ bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int
{ {
// http://www.opengl.org/wiki/Vertex_Specification_Best_Practices // http://www.opengl.org/wiki/Vertex_Specification_Best_Practices
if (size == m_parent->GetSize()) if (size == m_parent->GetSize())
glBufferData(bufferTarget[m_type], m_parent->GetSize(), nullptr, bufferUsage[m_parent->GetUsage()]); // Discard glBufferData(NzOpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, NzOpenGL::BufferUsage[m_parent->GetUsage()]); // Discard
glBufferSubData(bufferTarget[m_type], offset, size, data); glBufferSubData(NzOpenGL::BufferTarget[m_type], offset, size, data);
} }
else else
{ {
@ -170,12 +138,12 @@ bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int
std::memcpy(ptr, data, size); std::memcpy(ptr, data, size);
if (glUnmapBuffer(bufferTarget[m_type]) != GL_TRUE) if (glUnmapBuffer(NzOpenGL::BufferTarget[m_type]) != GL_TRUE)
{ {
// Une erreur rare est survenue, nous devons réinitialiser le buffer // Une erreur rare est survenue, nous devons réinitialiser le buffer
NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')'); NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')');
glBufferData(bufferTarget[m_type], m_parent->GetSize(), nullptr, bufferUsage[m_parent->GetStorage()]); glBufferData(NzOpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, NzOpenGL::BufferUsage[m_parent->GetStorage()]);
return false; return false;
} }
@ -183,7 +151,7 @@ bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérations chaînées) // Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérations chaînées)
if (previous != m_buffer && previous != 0) if (previous != m_buffer && previous != 0)
glBindBuffer(bufferTarget[m_type], previous); glBindBuffer(NzOpenGL::BufferTarget[m_type], previous);
return true; return true;
} }
@ -204,16 +172,16 @@ void* NzHardwareBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned
// Pour ne pas perturber le rendu, on interfère pas avec le binding déjà présent // Pour ne pas perturber le rendu, on interfère pas avec le binding déjà présent
GLuint previous; GLuint previous;
glGetIntegerv(bufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous)); glGetIntegerv(NzOpenGL::BufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous));
if (previous != m_buffer) if (previous != m_buffer)
glBindBuffer(bufferTarget[m_type], m_buffer); glBindBuffer(NzOpenGL::BufferTarget[m_type], m_buffer);
void* ptr = mapBuffer(m_type, access, offset, size); void* ptr = mapBuffer(m_type, access, offset, size);
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérrations chaînées) // Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérrations chaînées)
if (previous != m_buffer && previous != 0) if (previous != m_buffer && previous != 0)
glBindBuffer(bufferTarget[m_type], previous); glBindBuffer(NzOpenGL::BufferTarget[m_type], previous);
return ptr; return ptr;
} }
@ -223,28 +191,28 @@ bool NzHardwareBuffer::Unmap()
NzContext::EnsureContext(); NzContext::EnsureContext();
GLuint previous; GLuint previous;
glGetIntegerv(bufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous)); glGetIntegerv(NzOpenGL::BufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous));
if (previous != m_buffer) if (previous != m_buffer)
glBindBuffer(bufferTarget[m_type], m_buffer); glBindBuffer(NzOpenGL::BufferTarget[m_type], m_buffer);
if (glUnmapBuffer(bufferTarget[m_type]) != GL_TRUE) if (glUnmapBuffer(NzOpenGL::BufferTarget[m_type]) != GL_TRUE)
{ {
// Une erreur rare est survenue, nous devons réinitialiser le buffer // Une erreur rare est survenue, nous devons réinitialiser le buffer
NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')'); NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')');
glBufferData(bufferTarget[m_type], m_parent->GetSize(), nullptr, bufferUsage[m_parent->GetStorage()]); glBufferData(NzOpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, NzOpenGL::BufferUsage[m_parent->GetStorage()]);
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérations chaînées) // Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérations chaînées)
if (previous != m_buffer && previous != 0) if (previous != m_buffer && previous != 0)
glBindBuffer(bufferTarget[m_type], previous); glBindBuffer(NzOpenGL::BufferTarget[m_type], previous);
return false; return false;
} }
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérations chaînées) // Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérations chaînées)
if (previous != m_buffer && previous != 0) if (previous != m_buffer && previous != 0)
glBindBuffer(bufferTarget[m_type], previous); glBindBuffer(NzOpenGL::BufferTarget[m_type], previous);
return true; return true;
} }

View File

@ -14,21 +14,17 @@
NzOcclusionQuery::NzOcclusionQuery() : NzOcclusionQuery::NzOcclusionQuery() :
m_id(0) m_id(0)
{ {
#if NAZARA_RENDERER_SAFE
if (IsSupported()) if (IsSupported())
{ {
#endif
NzContext::EnsureContext(); NzContext::EnsureContext();
glGenQueries(1, reinterpret_cast<GLuint*>(&m_id)); glGenQueries(1, reinterpret_cast<GLuint*>(&m_id));
#if NAZARA_RENDERER_SAFE
} }
else else
{ {
NazaraError("Occlusion queries not supported"); NazaraError("Occlusion queries not supported");
return; return;
} }
#endif
#ifdef NAZARA_DEBUG #ifdef NAZARA_DEBUG
if (!m_id) if (!m_id)

View File

@ -1,4 +1,4 @@
// Copyright (C) 2012 Jérôme Leclercq // Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Renderer module" // This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
@ -58,7 +58,7 @@ namespace
} }
std::set<NzString> openGLextensionSet; std::set<NzString> openGLextensionSet;
bool openGLextensions[NzOpenGL::Max+1] = {false}; bool openGLextensions[nzOpenGLExtension_Max+1] = {false};
unsigned int openGLversion = 0; unsigned int openGLversion = 0;
bool LoadExtensionsString(const NzString& extensionString) bool LoadExtensionsString(const NzString& extensionString)
@ -69,7 +69,7 @@ namespace
return false; return false;
} }
// On peut sûrement faire plus rapide mais comme ça ne se fait qu'une fois et que NzString implémente le COW... // On peut sûrement faire plus rapide mais comme ça ne se fait qu'une fois et que NzString implémente le COW...
std::vector<NzString> ext; std::vector<NzString> ext;
extensionString.Split(ext); extensionString.Split(ext);
@ -106,17 +106,19 @@ namespace
} }
} }
NzOpenGLFunc NzOpenGL::GetEntry(const NzString& entryPoint) namespace NzOpenGL
{
NzOpenGLFunc GetEntry(const NzString& entryPoint)
{ {
return LoadEntry(entryPoint.GetConstBuffer(), false); return LoadEntry(entryPoint.GetConstBuffer(), false);
} }
unsigned int NzOpenGL::GetVersion() unsigned int GetVersion()
{ {
return openGLversion; return openGLversion;
} }
bool NzOpenGL::Initialize() bool Initialize()
{ {
if (!LoadLibrary()) if (!LoadLibrary())
{ {
@ -124,18 +126,18 @@ bool NzOpenGL::Initialize()
return false; return false;
} }
// Le chargement des fonctions OpenGL nécessite un contexte OpenGL // Le chargement des fonctions OpenGL nécessite un contexte OpenGL
NzContextParameters parameters; NzContextParameters parameters;
parameters.majorVersion = 2; parameters.majorVersion = 2;
parameters.minorVersion = 0; parameters.minorVersion = 0;
parameters.shared = false; parameters.shared = false;
/* /*
Note: Même le contexte de chargement nécessite quelques fonctions de base pour correctement s'initialiser Note: Même le contexte de chargement nécessite quelques fonctions de base pour correctement s'initialiser
Pour cette raison, deux contextes sont créés, le premier sert à récupérer les fonctions permetttant Pour cette raison, deux contextes sont créés, le premier sert à récupérer les fonctions permetttant
de créer le second avec les bons paramètres. de créer le second avec les bons paramètres.
Non sérieusement si quelqu'un a une meilleure idée qu'il me le dise Non sérieusement si quelqu'un a une meilleure idée qu'il me le dise.
*/ */
/****************************************Initialisation****************************************/ /****************************************Initialisation****************************************/
@ -158,9 +160,9 @@ bool NzOpenGL::Initialize()
glXCreateContextAttribs = reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(LoadEntry("glXCreateContextAttribsARB", false)); glXCreateContextAttribs = reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(LoadEntry("glXCreateContextAttribsARB", false));
#endif #endif
// Récupération de la version d'OpenGL // Récupération de la version d'OpenGL
// Ce code se base sur le fait que la carte graphique renverra un contexte de compatibilité avec la plus haute version supportée // Ce code se base sur le fait que la carte graphique renverra un contexte de compatibilité avec la plus haute version supportée
// Ce qui semble vrai au moins chez ATI/AMD et NVidia, mais si quelqu'un à une meilleure idée ... // Ce qui semble vrai au moins chez ATI/AMD et NVidia, mais si quelqu'un à une meilleure idée ...
glGetString = reinterpret_cast<PFNGLGETSTRINGPROC>(LoadEntry("glGetString", false)); glGetString = reinterpret_cast<PFNGLGETSTRINGPROC>(LoadEntry("glGetString", false));
if (!glGetString) if (!glGetString)
{ {
@ -197,7 +199,7 @@ bool NzOpenGL::Initialize()
openGLversion = major*100 + minor*10; openGLversion = major*100 + minor*10;
if (openGLversion < 200) if (openGLversion < 200)
{ {
NazaraError("OpenGL version is too low, please upgrade your drivers or your graphics card"); NazaraError("OpenGL version is too low, please upgrade your drivers or your video card");
Uninitialize(); Uninitialize();
return false; return false;
@ -207,8 +209,7 @@ bool NzOpenGL::Initialize()
parameters.majorVersion = NzContextParameters::defaultMajorVersion = major; parameters.majorVersion = NzContextParameters::defaultMajorVersion = major;
parameters.minorVersion = NzContextParameters::defaultMinorVersion = minor; parameters.minorVersion = NzContextParameters::defaultMinorVersion = minor;
// Destruction implicite du premier contexte if (!loadContext.Create(parameters)) // Destruction implicite du premier contexte
if (!loadContext.Create(parameters))
{ {
NazaraError("Failed to create load context"); NazaraError("Failed to create load context");
Uninitialize(); Uninitialize();
@ -286,9 +287,11 @@ bool NzOpenGL::Initialize()
glStencilFunc = reinterpret_cast<PFNGLSTENCILFUNCPROC>(LoadEntry("glStencilFunc")); glStencilFunc = reinterpret_cast<PFNGLSTENCILFUNCPROC>(LoadEntry("glStencilFunc"));
glStencilOp = reinterpret_cast<PFNGLSTENCILOPPROC>(LoadEntry("glStencilOp")); glStencilOp = reinterpret_cast<PFNGLSTENCILOPPROC>(LoadEntry("glStencilOp"));
glTexImage2D = reinterpret_cast<PFNGLTEXIMAGE2DPROC>(LoadEntry("glTexImage2D")); glTexImage2D = reinterpret_cast<PFNGLTEXIMAGE2DPROC>(LoadEntry("glTexImage2D"));
glTexImage3D = reinterpret_cast<PFNGLTEXIMAGE3DPROC>(LoadEntry("glTexImage3D"));
glTexParameterf = reinterpret_cast<PFNGLTEXPARAMETERFPROC>(LoadEntry("glTexParameterf")); glTexParameterf = reinterpret_cast<PFNGLTEXPARAMETERFPROC>(LoadEntry("glTexParameterf"));
glTexParameteri = reinterpret_cast<PFNGLTEXPARAMETERIPROC>(LoadEntry("glTexParameteri")); glTexParameteri = reinterpret_cast<PFNGLTEXPARAMETERIPROC>(LoadEntry("glTexParameteri"));
glTexSubImage2D = reinterpret_cast<PFNGLTEXSUBIMAGE2DPROC>(LoadEntry("glTexSubImage2D")); glTexSubImage2D = reinterpret_cast<PFNGLTEXSUBIMAGE2DPROC>(LoadEntry("glTexSubImage2D"));
glTexSubImage3D = reinterpret_cast<PFNGLTEXSUBIMAGE3DPROC>(LoadEntry("glTexSubImage3D"));
glUniform1f = reinterpret_cast<PFNGLUNIFORM1FPROC>(LoadEntry("glUniform1f")); glUniform1f = reinterpret_cast<PFNGLUNIFORM1FPROC>(LoadEntry("glUniform1f"));
glUniform1i = reinterpret_cast<PFNGLUNIFORM1IPROC>(LoadEntry("glUniform1i")); glUniform1i = reinterpret_cast<PFNGLUNIFORM1IPROC>(LoadEntry("glUniform1i"));
glUniform2fv = reinterpret_cast<PFNGLUNIFORM2FVPROC>(LoadEntry("glUniform2fv")); glUniform2fv = reinterpret_cast<PFNGLUNIFORM2FVPROC>(LoadEntry("glUniform2fv"));
@ -311,6 +314,11 @@ bool NzOpenGL::Initialize()
/****************************************Extensions****************************************/ /****************************************Extensions****************************************/
// Fonctions optionnelles
glBindFragDataLocation = reinterpret_cast<PFNGLBINDFRAGDATALOCATIONPROC>(LoadEntry("glBindFragDataLocation", false));
if (!glBindFragDataLocation)
glBindFragDataLocation = reinterpret_cast<PFNGLBINDFRAGDATALOCATIONEXTPROC>(LoadEntry("glBindFragDataLocationEXT", false));
glGetStringi = reinterpret_cast<PFNGLGETSTRINGIPROC>(LoadEntry("glGetStringi", false)); glGetStringi = reinterpret_cast<PFNGLGETSTRINGIPROC>(LoadEntry("glGetStringi", false));
glMapBufferRange = reinterpret_cast<PFNGLMAPBUFFERRANGEPROC>(LoadEntry("glMapBufferRange", false)); glMapBufferRange = reinterpret_cast<PFNGLMAPBUFFERRANGEPROC>(LoadEntry("glMapBufferRange", false));
@ -347,7 +355,7 @@ bool NzOpenGL::Initialize()
#endif #endif
// AnisotropicFilter // AnisotropicFilter
openGLextensions[NzOpenGL::AnisotropicFilter] = IsSupported("GL_EXT_texture_filter_anisotropic"); openGLextensions[nzOpenGLExtension_AnisotropicFilter] = IsSupported("GL_EXT_texture_filter_anisotropic");
// DebugOutput // DebugOutput
if (openGLversion >= 430 || IsSupported("GL_KHR_debug")) if (openGLversion >= 430 || IsSupported("GL_KHR_debug"))
@ -359,7 +367,7 @@ bool NzOpenGL::Initialize()
glDebugMessageInsert = reinterpret_cast<PFNGLDEBUGMESSAGEINSERTPROC>(LoadEntry("glDebugMessageInsert")); glDebugMessageInsert = reinterpret_cast<PFNGLDEBUGMESSAGEINSERTPROC>(LoadEntry("glDebugMessageInsert"));
glGetDebugMessageLog = reinterpret_cast<PFNGLGETDEBUGMESSAGELOGPROC>(LoadEntry("glGetDebugMessageLog")); glGetDebugMessageLog = reinterpret_cast<PFNGLGETDEBUGMESSAGELOGPROC>(LoadEntry("glGetDebugMessageLog"));
openGLextensions[NzOpenGL::DebugOutput] = true; openGLextensions[nzOpenGLExtension_DebugOutput] = true;
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
@ -367,7 +375,7 @@ bool NzOpenGL::Initialize()
} }
} }
if (!openGLextensions[NzOpenGL::DebugOutput] && IsSupported("GL_ARB_debug_output")) if (!openGLextensions[nzOpenGLExtension_DebugOutput] && IsSupported("GL_ARB_debug_output"))
{ {
try try
{ {
@ -376,7 +384,7 @@ bool NzOpenGL::Initialize()
glDebugMessageInsert = reinterpret_cast<PFNGLDEBUGMESSAGEINSERTARBPROC>(LoadEntry("glDebugMessageInsertARB")); glDebugMessageInsert = reinterpret_cast<PFNGLDEBUGMESSAGEINSERTARBPROC>(LoadEntry("glDebugMessageInsertARB"));
glGetDebugMessageLog = reinterpret_cast<PFNGLGETDEBUGMESSAGELOGARBPROC>(LoadEntry("glGetDebugMessageLogARB")); glGetDebugMessageLog = reinterpret_cast<PFNGLGETDEBUGMESSAGELOGARBPROC>(LoadEntry("glGetDebugMessageLogARB"));
openGLextensions[NzOpenGL::DebugOutput] = true; openGLextensions[nzOpenGLExtension_DebugOutput] = true;
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
@ -394,7 +402,7 @@ bool NzOpenGL::Initialize()
glUniform3dv = reinterpret_cast<PFNGLUNIFORM3DVPROC>(LoadEntry("glUniform3dv")); glUniform3dv = reinterpret_cast<PFNGLUNIFORM3DVPROC>(LoadEntry("glUniform3dv"));
glUniform4dv = reinterpret_cast<PFNGLUNIFORM4DVPROC>(LoadEntry("glUniform4dv")); glUniform4dv = reinterpret_cast<PFNGLUNIFORM4DVPROC>(LoadEntry("glUniform4dv"));
openGLextensions[NzOpenGL::FP64] = true; openGLextensions[nzOpenGLExtension_FP64] = true;
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
@ -413,13 +421,17 @@ bool NzOpenGL::Initialize()
glDeleteFramebuffers = reinterpret_cast<PFNGLDELETEFRAMEBUFFERSPROC>(LoadEntry("glDeleteFramebuffers")); glDeleteFramebuffers = reinterpret_cast<PFNGLDELETEFRAMEBUFFERSPROC>(LoadEntry("glDeleteFramebuffers"));
glDeleteRenderbuffers = reinterpret_cast<PFNGLDELETERENDERBUFFERSPROC>(LoadEntry("glDeleteRenderbuffers")); glDeleteRenderbuffers = reinterpret_cast<PFNGLDELETERENDERBUFFERSPROC>(LoadEntry("glDeleteRenderbuffers"));
glFramebufferRenderbuffer = reinterpret_cast<PFNGLFRAMEBUFFERRENDERBUFFERPROC>(LoadEntry("glFramebufferRenderbuffer")); glFramebufferRenderbuffer = reinterpret_cast<PFNGLFRAMEBUFFERRENDERBUFFERPROC>(LoadEntry("glFramebufferRenderbuffer"));
glFramebufferTexture = reinterpret_cast<PFNGLFRAMEBUFFERTEXTUREPROC>(LoadEntry("glFramebufferTexture"));
glFramebufferTexture1D = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE1DPROC>(LoadEntry("glFramebufferTexture1D"));
glFramebufferTexture2D = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE2DPROC>(LoadEntry("glFramebufferTexture2D")); glFramebufferTexture2D = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE2DPROC>(LoadEntry("glFramebufferTexture2D"));
glFramebufferTexture3D = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE3DPROC>(LoadEntry("glFramebufferTexture3D"));
glFramebufferTextureLayer = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURELAYERPROC>(LoadEntry("glFramebufferTextureLayer"));
glGenerateMipmap = reinterpret_cast<PFNGLGENERATEMIPMAPPROC>(LoadEntry("glGenerateMipmap")); glGenerateMipmap = reinterpret_cast<PFNGLGENERATEMIPMAPPROC>(LoadEntry("glGenerateMipmap"));
glGenFramebuffers = reinterpret_cast<PFNGLGENFRAMEBUFFERSPROC>(LoadEntry("glGenFramebuffers")); glGenFramebuffers = reinterpret_cast<PFNGLGENFRAMEBUFFERSPROC>(LoadEntry("glGenFramebuffers"));
glGenRenderbuffers = reinterpret_cast<PFNGLGENRENDERBUFFERSPROC>(LoadEntry("glGenRenderbuffers")); glGenRenderbuffers = reinterpret_cast<PFNGLGENRENDERBUFFERSPROC>(LoadEntry("glGenRenderbuffers"));
glRenderbufferStorage = reinterpret_cast<PFNGLRENDERBUFFERSTORAGEPROC>(LoadEntry("glRenderbufferStorage")); glRenderbufferStorage = reinterpret_cast<PFNGLRENDERBUFFERSTORAGEPROC>(LoadEntry("glRenderbufferStorage"));
openGLextensions[NzOpenGL::FrameBufferObject] = true; openGLextensions[nzOpenGLExtension_FrameBufferObject] = true;
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
@ -428,7 +440,7 @@ bool NzOpenGL::Initialize()
} }
// PixelBufferObject // PixelBufferObject
openGLextensions[NzOpenGL::PixelBufferObject] = (openGLversion >= 210 || IsSupported("GL_ARB_pixel_buffer_object")); openGLextensions[nzOpenGLExtension_PixelBufferObject] = (openGLversion >= 210 || IsSupported("GL_ARB_pixel_buffer_object"));
// SeparateShaderObjects // SeparateShaderObjects
if (openGLversion >= 400 || IsSupported("GL_ARB_separate_shader_objects")) if (openGLversion >= 400 || IsSupported("GL_ARB_separate_shader_objects"))
@ -440,8 +452,8 @@ bool NzOpenGL::Initialize()
glProgramUniform4fv = reinterpret_cast<PFNGLPROGRAMUNIFORM4FVPROC>(LoadEntry("glProgramUniform4fv")); glProgramUniform4fv = reinterpret_cast<PFNGLPROGRAMUNIFORM4FVPROC>(LoadEntry("glProgramUniform4fv"));
glProgramUniformMatrix4fv = reinterpret_cast<PFNGLPROGRAMUNIFORMMATRIX4FVPROC>(LoadEntry("glProgramUniformMatrix4fv")); glProgramUniformMatrix4fv = reinterpret_cast<PFNGLPROGRAMUNIFORMMATRIX4FVPROC>(LoadEntry("glProgramUniformMatrix4fv"));
// Si ARB_gpu_shader_fp64 est supporté, alors cette extension donne également accès aux fonctions utilisant des double // Si ARB_gpu_shader_fp64 est supporté, alors cette extension donne également accès aux fonctions utilisant des double
if (openGLextensions[NzOpenGL::FP64]) if (openGLextensions[nzOpenGLExtension_FP64])
{ {
glProgramUniform1d = reinterpret_cast<PFNGLPROGRAMUNIFORM1DPROC>(LoadEntry("glProgramUniform1d")); glProgramUniform1d = reinterpret_cast<PFNGLPROGRAMUNIFORM1DPROC>(LoadEntry("glProgramUniform1d"));
glProgramUniform2dv = reinterpret_cast<PFNGLPROGRAMUNIFORM2DVPROC>(LoadEntry("glProgramUniform2dv")); glProgramUniform2dv = reinterpret_cast<PFNGLPROGRAMUNIFORM2DVPROC>(LoadEntry("glProgramUniform2dv"));
@ -450,45 +462,14 @@ bool NzOpenGL::Initialize()
glProgramUniformMatrix4dv = reinterpret_cast<PFNGLPROGRAMUNIFORMMATRIX4DVPROC>(LoadEntry("glProgramUniformMatrix4dv")); glProgramUniformMatrix4dv = reinterpret_cast<PFNGLPROGRAMUNIFORMMATRIX4DVPROC>(LoadEntry("glProgramUniformMatrix4dv"));
} }
openGLextensions[NzOpenGL::SeparateShaderObjects] = true; openGLextensions[nzOpenGLExtension_SeparateShaderObjects] = true;
}
// Texture3D
try
{
glTexImage3D = reinterpret_cast<PFNGLTEXIMAGE3DPROC>(LoadEntry("glTexImage3D"));
glTexSubImage3D = reinterpret_cast<PFNGLTEXSUBIMAGE3DPROC>(LoadEntry("glTexSubImage3D"));
openGLextensions[NzOpenGL::Texture3D] = true;
}
catch (const std::exception& e)
{
NazaraWarning("Failed to load core texture 3D (" + NzString(e.what()) + ")");
if (IsSupported("GL_EXT_texture3D"))
{
try
{
// Hacky: Normalement incompatible à cause du internalFormat, GLenum pour l'extension et GLint pour le noyau
// Mais la taille du type étant la même (GLenum est un typedef équivalent à GLint) et Nazara n'utilisant pas
// Ce qui cause l'incompatibilité (les paramètres 1,2,3,4), je prends cette liberté
glTexImage3D = reinterpret_cast<PFNGLTEXIMAGE3DPROC>(LoadEntry("glTexImage3DEXT"));
glTexSubImage3D = reinterpret_cast<PFNGLTEXSUBIMAGE3DEXTPROC>(LoadEntry("glTexSubImage3DEXT"));
openGLextensions[NzOpenGL::Texture3D] = true;
}
catch (const std::exception& e2)
{
NazaraWarning("Failed to load EXT_texture3D: " + NzString(e2.what()));
}
}
} }
// TextureArray // TextureArray
openGLextensions[NzOpenGL::TextureArray] = (openGLversion >= 300 || IsSupported("GL_EXT_texture_array")); openGLextensions[nzOpenGLExtension_TextureArray] = (openGLversion >= 300 || IsSupported("GL_EXT_texture_array"));
// TextureCompression_s3tc // TextureCompression_s3tc
openGLextensions[NzOpenGL::TextureCompression_s3tc] = IsSupported("GL_EXT_texture_compression_s3tc"); openGLextensions[nzOpenGLExtension_TextureCompression_s3tc] = IsSupported("GL_EXT_texture_compression_s3tc");
// TextureStorage // TextureStorage
if (openGLversion >= 420 || IsSupported("GL_ARB_texture_storage")) if (openGLversion >= 420 || IsSupported("GL_ARB_texture_storage"))
@ -499,7 +480,7 @@ bool NzOpenGL::Initialize()
glTexStorage2D = reinterpret_cast<PFNGLTEXSTORAGE2DPROC>(LoadEntry("glTexStorage2D")); glTexStorage2D = reinterpret_cast<PFNGLTEXSTORAGE2DPROC>(LoadEntry("glTexStorage2D"));
glTexStorage3D = reinterpret_cast<PFNGLTEXSTORAGE3DPROC>(LoadEntry("glTexStorage3D")); glTexStorage3D = reinterpret_cast<PFNGLTEXSTORAGE3DPROC>(LoadEntry("glTexStorage3D"));
openGLextensions[NzOpenGL::TextureStorage] = true; openGLextensions[nzOpenGLExtension_TextureStorage] = true;
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
@ -516,7 +497,7 @@ bool NzOpenGL::Initialize()
glDeleteVertexArrays = reinterpret_cast<PFNGLDELETEVERTEXARRAYSPROC>(LoadEntry("glDeleteVertexArrays")); glDeleteVertexArrays = reinterpret_cast<PFNGLDELETEVERTEXARRAYSPROC>(LoadEntry("glDeleteVertexArrays"));
glGenVertexArrays = reinterpret_cast<PFNGLGENVERTEXARRAYSPROC>(LoadEntry("glGenVertexArrays")); glGenVertexArrays = reinterpret_cast<PFNGLGENVERTEXARRAYSPROC>(LoadEntry("glGenVertexArrays"));
openGLextensions[NzOpenGL::VertexArrayObject] = true; openGLextensions[nzOpenGLExtension_VertexArrayObject] = true;
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
@ -528,9 +509,9 @@ bool NzOpenGL::Initialize()
if (!glGenerateMipmap) if (!glGenerateMipmap)
glGenerateMipmap = reinterpret_cast<PFNGLGENERATEMIPMAPEXTPROC>(LoadEntry("glGenerateMipmapEXT", false)); glGenerateMipmap = reinterpret_cast<PFNGLGENERATEMIPMAPEXTPROC>(LoadEntry("glGenerateMipmapEXT", false));
/****************************************Contexte de référence****************************************/ /****************************************Contexte de référence****************************************/
///FIXME: Utiliser le contexte de chargement comme référence ? (Vérifier mode debug) ///FIXME: Utiliser le contexte de chargement comme référence ? (Vérifier mode debug)
if (!NzContext::Initialize()) if (!NzContext::Initialize())
{ {
NazaraError("Failed to initialize contexts"); NazaraError("Failed to initialize contexts");
@ -544,17 +525,155 @@ bool NzOpenGL::Initialize()
return true; return true;
} }
bool NzOpenGL::IsSupported(Extension extension) bool IsSupported(nzOpenGLExtension extension)
{ {
return openGLextensions[extension]; return openGLextensions[extension];
} }
bool NzOpenGL::IsSupported(const NzString& string) bool IsSupported(const NzString& string)
{ {
return openGLextensionSet.find(string) != openGLextensionSet.end(); return openGLextensionSet.find(string) != openGLextensionSet.end();
} }
void NzOpenGL::Uninitialize() bool TranslateFormat(nzPixelFormat pixelFormat, Format* format, FormatType type)
{
switch (pixelFormat)
{
case nzPixelFormat_BGR8:
format->dataFormat = GL_BGR;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_RGB8;
return true;
case nzPixelFormat_BGRA8:
format->dataFormat = GL_BGRA;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_RGBA8;
return true;
case nzPixelFormat_DXT1:
format->dataFormat = GL_RGB;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
return true;
case nzPixelFormat_DXT3:
format->dataFormat = GL_RGBA;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
return true;
case nzPixelFormat_DXT5:
format->dataFormat = GL_RGBA;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
return true;
case nzPixelFormat_L8:
case nzPixelFormat_LA8:
return false;
case nzPixelFormat_RGB5A1:
format->dataFormat = GL_RGBA;
format->dataType = GL_UNSIGNED_SHORT_5_5_5_1;
format->internalFormat = GL_RGB5_A1;
return true;
case nzPixelFormat_RGB8:
format->dataFormat = GL_RGB;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_RGB8;
return true;
case nzPixelFormat_RGBA4:
format->dataFormat = GL_RGBA;
format->dataType = GL_UNSIGNED_SHORT_4_4_4_4;
format->internalFormat = GL_RGBA4;
return true;
case nzPixelFormat_RGBA8:
format->dataFormat = GL_RGBA;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_RGBA8;
return true;
case nzPixelFormat_Depth16:
format->dataFormat = GL_DEPTH_COMPONENT;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_DEPTH_COMPONENT16;
return true;
case nzPixelFormat_Depth24:
format->dataFormat = GL_DEPTH_COMPONENT;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_DEPTH_COMPONENT24;
return true;
case nzPixelFormat_Depth24Stencil8:
format->dataFormat = GL_DEPTH_STENCIL;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_DEPTH24_STENCIL8;
return true;
case nzPixelFormat_Depth32:
format->dataFormat = GL_DEPTH_COMPONENT;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_DEPTH_COMPONENT32;
return true;
case nzPixelFormat_Stencil1:
if (type == FormatType_Texture) // Les formats de stencil ne sont pas supportés par les textures
return false;
else
{
format->dataFormat = GL_NONE;
format->dataType = GL_NONE;
format->internalFormat = GL_STENCIL_INDEX1;
return true;
}
case nzPixelFormat_Stencil4:
if (type == FormatType_Texture)
return false;
else
{
format->dataFormat = GL_NONE;
format->dataType = GL_NONE;
format->internalFormat = GL_STENCIL_INDEX4;
return true;
}
case nzPixelFormat_Stencil8:
if (type == FormatType_Texture)
return false;
else
{
format->dataFormat = GL_NONE;
format->dataType = GL_NONE;
format->internalFormat = GL_STENCIL_INDEX8;
return true;
}
case nzPixelFormat_Stencil16:
if (type == FormatType_Texture)
return false;
else
{
format->dataFormat = GL_NONE;
format->dataType = GL_NONE;
format->internalFormat = GL_STENCIL_INDEX16;
return true;
}
case nzPixelFormat_Undefined:
break;
}
NazaraError("Invalid pixel format");
return false;
}
void Uninitialize()
{ {
NzContext::Uninitialize(); NzContext::Uninitialize();
@ -567,12 +686,200 @@ void NzOpenGL::Uninitialize()
UnloadLibrary(); UnloadLibrary();
} }
GLenum Attachment[nzAttachmentPoint_Max+1] =
{
GL_COLOR_ATTACHMENT0, // nzAttachmentPoint_Color
GL_DEPTH_ATTACHMENT, // nzAttachmentPoint_Depth
GL_DEPTH_STENCIL_ATTACHMENT, // nzAttachmentPoint_DepthStencil
GL_STENCIL_ATTACHMENT // nzAttachmentPoint_Stencil
};
nzUInt8 AttributeIndex[nzElementUsage_Max+1] =
{
2, // nzElementUsage_Diffuse
1, // nzElementUsage_Normal
0, // nzElementUsage_Position
3, // nzElementUsage_Tangent
4 // nzElementUsage_TexCoord (Doit être le dernier de la liste car extensible)
};
GLenum BlendFunc[nzBlendFunc_Max+1] =
{
GL_DST_ALPHA, // nzBlendFunc_DestAlpha
GL_DST_COLOR, // nzBlendFunc_DestColor
GL_SRC_ALPHA, // nzBlendFunc_SrcAlpha
GL_SRC_COLOR, // nzBlendFunc_SrcColor
GL_ONE_MINUS_DST_ALPHA, // nzBlendFunc_InvDestAlpha
GL_ONE_MINUS_DST_COLOR, // nzBlendFunc_InvDestColor
GL_ONE_MINUS_SRC_ALPHA, // nzBlendFunc_InvSrcAlpha
GL_ONE_MINUS_SRC_COLOR, // nzBlendFunc_InvSrcColor
GL_ONE, // nzBlendFunc_One
GL_ZERO // nzBlendFunc_Zero
};
GLenum BufferLock[nzBufferAccess_Max+1] =
{
GL_WRITE_ONLY, // nzBufferAccess_DiscardAndWrite
GL_READ_ONLY, // nzBufferAccess_ReadOnly
GL_READ_WRITE, // nzBufferAccess_ReadWrite
GL_WRITE_ONLY // nzBufferAccess_WriteOnly
};
GLenum BufferLockRange[nzBufferAccess_Max+1] =
{
GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_DiscardAndWrite
GL_MAP_READ_BIT, // nzBufferAccess_ReadOnly
GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_ReadWrite
GL_MAP_WRITE_BIT // nzBufferAccess_WriteOnly
};
GLenum BufferTarget[nzBufferType_Max+1] =
{
GL_ELEMENT_ARRAY_BUFFER, // nzBufferType_Index,
GL_ARRAY_BUFFER, // nzBufferType_Vertex
};
GLenum BufferTargetBinding[nzBufferType_Max+1] =
{
GL_ELEMENT_ARRAY_BUFFER_BINDING, // nzBufferType_Index,
GL_ARRAY_BUFFER_BINDING, // nzBufferType_Vertex
};
GLenum BufferUsage[nzBufferUsage_Max+1] =
{
// J'ai choisi DYNAMIC à la place de STREAM car DYNAMIC semble plus adapté au profil "une mise à jour pour quelques rendus"
// Ce qui est je pense le scénario qui arrivera le plus souvent (Prévoir une option pour permettre d'utiliser le STREAM_DRAW ?)
// Source: http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=160839
GL_DYNAMIC_DRAW, // nzBufferUsage_Dynamic
GL_STATIC_DRAW // nzBufferUsage_Static
};
GLenum CubemapFace[6] =
{
GL_TEXTURE_CUBE_MAP_POSITIVE_X, // nzCubemapFace_PositiveX
GL_TEXTURE_CUBE_MAP_NEGATIVE_X, // nzCubemapFace_NegativeX
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, // nzCubemapFace_PositiveY
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, // nzCubemapFace_NegativeY
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, // nzCubemapFace_PositiveZ
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z // nzCubemapFace_NegativeZ
};
GLenum ElementType[nzElementType_Max+1] =
{
GL_UNSIGNED_BYTE, // nzElementType_Color
GL_DOUBLE, // nzElementType_Double1
GL_DOUBLE, // nzElementType_Double2
GL_DOUBLE, // nzElementType_Double3
GL_DOUBLE, // nzElementType_Double4
GL_FLOAT, // nzElementType_Float1
GL_FLOAT, // nzElementType_Float2
GL_FLOAT, // nzElementType_Float3
GL_FLOAT // nzElementType_Float4
};
GLenum FaceCulling[nzFaceCulling_Max+1] =
{
GL_BACK, // nzFaceCulling_Back
GL_FRONT, // nzFaceCulling_Front
GL_FRONT_AND_BACK // nzFaceCulling_FrontAndBack
};
GLenum FaceFilling[nzFaceFilling_Max+1] =
{
GL_POINT, // nzFaceFilling_Point
GL_LINE, // nzFaceFilling_Line
GL_FILL // nzFaceFilling_Fill
};
GLenum PrimitiveType[nzPrimitiveType_Max+1] =
{
GL_LINES, // nzPrimitiveType_LineList,
GL_LINE_STRIP, // nzPrimitiveType_LineStrip,
GL_POINTS, // nzPrimitiveType_PointList,
GL_TRIANGLES, // nzPrimitiveType_TriangleList,
GL_TRIANGLE_STRIP, // nzPrimitiveType_TriangleStrip,
GL_TRIANGLE_FAN // nzPrimitiveType_TriangleFan
};
GLenum RendererComparison[nzRendererComparison_Max+1] =
{
GL_ALWAYS, // nzRendererComparison_Always
GL_EQUAL, // nzRendererComparison_Equal
GL_GREATER, // nzRendererComparison_Greater
GL_GEQUAL, // nzRendererComparison_GreaterOrEqual
GL_LESS, // nzRendererComparison_Less
GL_LEQUAL, // nzRendererComparison_LessOrEqual
GL_NEVER // nzRendererComparison_Never
};
GLenum RendererParameter[nzRendererParameter_Max+1] =
{
GL_BLEND, // nzRendererParameter_Blend
GL_NONE, // nzRendererParameter_ColorWrite
GL_DEPTH_TEST, // nzRendererParameter_DepthTest
GL_NONE, // nzRendererParameter_DepthWrite
GL_CULL_FACE, // nzRendererParameter_FaceCulling
GL_STENCIL_TEST // nzRendererParameter_Stencil
};
GLenum ShaderType[nzShaderType_Max+1] =
{
GL_FRAGMENT_SHADER, // nzShaderType_Fragment
GL_GEOMETRY_SHADER, // nzShaderType_Geometry
GL_VERTEX_SHADER // nzShaderType_Vertex
};
GLenum StencilOperation[nzStencilOperation_Max+1] =
{
GL_DECR, // nzStencilOperation_Decrement
GL_DECR_WRAP, // nzStencilOperation_DecrementToSaturation
GL_INCR, // nzStencilOperation_Increment
GL_INCR_WRAP, // nzStencilOperation_IncrementToSaturation
GL_INVERT, // nzStencilOperation_Invert
GL_KEEP, // nzStencilOperation_Keep
GL_REPLACE, // nzStencilOperation_Replace
GL_ZERO // nzStencilOperation_Zero
};
GLenum TextureTarget[nzImageType_Max+1]
{
GL_TEXTURE_1D, // nzImageType_1D
GL_TEXTURE_1D_ARRAY, // nzImageType_1D_Array
GL_TEXTURE_2D, // nzImageType_2D
GL_TEXTURE_2D_ARRAY, // nzImageType_2D_Array
GL_TEXTURE_3D, // nzImageType_3D
GL_TEXTURE_CUBE_MAP // nzImageType_Cubemap
};
GLenum TextureTargetBinding[nzImageType_Max+1]
{
GL_TEXTURE_BINDING_1D, // nzImageType_1D
GL_TEXTURE_BINDING_1D_ARRAY, // nzImageType_1D_Array
GL_TEXTURE_BINDING_2D, // nzImageType_2D
GL_TEXTURE_BINDING_2D_ARRAY, // nzImageType_2D_Array
GL_TEXTURE_BINDING_3D, // nzImageType_3D
GL_TEXTURE_BINDING_CUBE_MAP // nzImageType_Cubemap
};
GLenum TextureTargetProxy[nzImageType_Max+1]
{
GL_PROXY_TEXTURE_1D, // nzImageType_1D
GL_PROXY_TEXTURE_1D_ARRAY, // nzImageType_1D_Array
GL_PROXY_TEXTURE_2D, // nzImageType_2D
GL_PROXY_TEXTURE_2D_ARRAY, // nzImageType_2D_Array
GL_PROXY_TEXTURE_3D, // nzImageType_3D
GL_PROXY_TEXTURE_CUBE_MAP // nzImageType_Cubemap
};
}
PFNGLACTIVETEXTUREPROC glActiveTexture = nullptr; PFNGLACTIVETEXTUREPROC glActiveTexture = nullptr;
PFNGLATTACHSHADERPROC glAttachShader = nullptr; PFNGLATTACHSHADERPROC glAttachShader = nullptr;
PFNGLBEGINQUERYPROC glBeginQuery = nullptr; PFNGLBEGINQUERYPROC glBeginQuery = nullptr;
PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation = nullptr; PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation = nullptr;
PFNGLBINDBUFFERPROC glBindBuffer = nullptr; PFNGLBINDBUFFERPROC glBindBuffer = nullptr;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = nullptr; PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = nullptr;
PFNGLBINDFRAGDATALOCATIONPROC glBindFragDataLocation = nullptr;
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = nullptr; PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = nullptr;
PFNGLBINDTEXTUREPROC glBindTexture = nullptr; PFNGLBINDTEXTUREPROC glBindTexture = nullptr;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr; PFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr;
@ -612,7 +919,11 @@ PFNGLDRAWELEMENTSPROC glDrawElements = nullptr;
PFNGLENDQUERYPROC glEndQuery = nullptr; PFNGLENDQUERYPROC glEndQuery = nullptr;
PFNGLFLUSHPROC glFlush = nullptr; PFNGLFLUSHPROC glFlush = nullptr;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = nullptr; PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = nullptr;
PFNGLFRAMEBUFFERTEXTUREPROC glFramebufferTexture = nullptr;
PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D = nullptr;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = nullptr; PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = nullptr;
PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D = nullptr;
PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = nullptr;
PFNGLENABLEPROC glEnable = nullptr; PFNGLENABLEPROC glEnable = nullptr;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr; PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr;
PFNGLGENERATEMIPMAPPROC glGenerateMipmap = nullptr; PFNGLGENERATEMIPMAPPROC glGenerateMipmap = nullptr;

View File

@ -0,0 +1,728 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/RenderTexture.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Renderer/Context.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <vector>
#include <Nazara/Renderer/Debug.hpp>
namespace
{
struct Attachment
{
union
{
GLuint buffer;
NzTexture* texture;
};
bool isBuffer;
bool isUsed = false;
};
unsigned int attachmentIndex[nzAttachmentPoint_Max+1] =
{
2, // nzAttachmentPoint_Color
0, // nzAttachmentPoint_Depth
0, // nzAttachmentPoint_DepthStencil
1 // nzAttachmentPoint_Stencil
};
nzAttachmentPoint formatTypeToAttachment[nzPixelFormatType_Max+1] =
{
nzAttachmentPoint_Color, // nzPixelFormatType_Color
nzAttachmentPoint_Depth, // nzPixelFormatType_Depth
nzAttachmentPoint_DepthStencil, // nzPixelFormatType_DepthStencil
nzAttachmentPoint_Stencil // nzPixelFormatType_Stencil
};
GLuint lockedPrevious = 0;
nzUInt8 lockedLevel = 0;
}
struct NzRenderTextureImpl
{
GLuint fbo;
std::vector<Attachment> attachements;
std::vector<GLenum> drawBuffers;
NzContext* context;
bool checked = false;
bool complete = false;
bool drawBuffersUpdated = true;
unsigned int height;
unsigned int width;
};
NzRenderTexture::~NzRenderTexture()
{
Destroy();
}
bool NzRenderTexture::AttachBuffer(nzAttachmentPoint attachmentPoint, nzUInt8 index, nzPixelFormat format)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Render texture not created");
return false;
}
if (attachmentPoint != nzAttachmentPoint_Color && index > 0)
{
NazaraError("Index must be 0 for non-color attachments");
return false;
}
unsigned int depthStencilIndex = attachmentIndex[nzAttachmentPoint_DepthStencil];
if (attachmentPoint == nzAttachmentPoint_Stencil && m_impl->attachements.size() > depthStencilIndex &&
m_impl->attachements[depthStencilIndex].isUsed)
{
NazaraError("Stencil target already attached by DepthStencil attachment");
return false;
}
if (formatTypeToAttachment[NzPixelFormat::GetType(format)] != attachmentPoint)
{
NazaraError("Pixel format type does not match attachment point type");
return false;
}
#endif
NzOpenGL::Format openglFormat;
if (!NzOpenGL::TranslateFormat(format, &openglFormat, NzOpenGL::FormatType_RenderBuffer))
{
NazaraError("Failed to translate pixel format into OpenGL format");
return false;
}
if (!Lock())
{
NazaraError("Failed to lock render texture");
return false;
}
// Détachement de l'attache précédente (Si il y a)
Detach(attachmentPoint, index);
GLuint renderBuffer = 0;
glGenRenderbuffers(1, &renderBuffer);
if (!renderBuffer)
{
NazaraError("Failed to create renderbuffer");
return false;
}
GLint previous;
glGetIntegerv(GL_RENDERBUFFER_BINDING, &previous);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, openglFormat.internalFormat, m_impl->width, m_impl->height);
if (previous != 0)
glBindRenderbuffer(GL_RENDERBUFFER, previous);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, GL_RENDERBUFFER, renderBuffer);
Unlock();
unsigned int minSize = attachmentIndex[attachmentPoint]+index+1;
if (m_impl->attachements.size() < minSize)
m_impl->attachements.resize(minSize);
Attachment& attachment = m_impl->attachements[minSize-1];
attachment.isBuffer = true;
attachment.isUsed = true;
attachment.buffer = renderBuffer;
m_impl->checked = false;
m_impl->drawBuffersUpdated = false;
return true;
}
bool NzRenderTexture::AttachTexture(nzAttachmentPoint attachmentPoint, nzUInt8 index, NzTexture* texture)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Render texture not created");
return false;
}
if (attachmentPoint != nzAttachmentPoint_Color && index > 0)
{
NazaraError("Index must be 0 for non-color attachments");
return false;
}
unsigned int depthStencilIndex = attachmentIndex[nzAttachmentPoint_DepthStencil];
if (attachmentPoint == nzAttachmentPoint_Stencil && m_impl->attachements.size() > depthStencilIndex &&
m_impl->attachements[depthStencilIndex].isUsed)
{
NazaraError("Stencil target already attached by DepthStencil attachment");
return false;
}
if (!texture || !texture->IsValid())
{
NazaraError("Invalid texture");
return false;
}
if (texture->GetWidth() < m_impl->width || texture->GetHeight() < m_impl->height)
{
NazaraError("Texture cannot be smaller than render texture");
return false;
}
if (texture->GetRenderTexture() != nullptr)
{
NazaraError("Texture already used by another render texture");
return false;
}
if (formatTypeToAttachment[NzPixelFormat::GetType(texture->GetFormat())] != attachmentPoint)
{
NazaraError("Pixel format type does not match attachment point type");
return false;
}
#endif
if (!Lock())
{
NazaraError("Failed to lock render texture");
return false;
}
// Détachement de l'attache précédente (Si il y a)
Detach(attachmentPoint, index);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, texture->GetOpenGLID(), 0);
Unlock();
unsigned int minSize = attachmentIndex[attachmentPoint]+index+1;
if (m_impl->attachements.size() < minSize)
m_impl->attachements.resize(minSize);
Attachment& attachment = m_impl->attachements[minSize-1];
attachment.isBuffer = true;
attachment.isUsed = true;
attachment.texture = texture;
texture->AddResourceListener(this, minSize-1);
texture->SetRenderTexture(this);
m_impl->checked = false;
m_impl->drawBuffersUpdated = false;
return true;
}
bool NzRenderTexture::AttachTexture(nzAttachmentPoint attachmentPoint, nzUInt8 index, NzTexture* texture, unsigned int z)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Render texture not created");
return false;
}
if (attachmentPoint != nzAttachmentPoint_Color && index > 0)
{
NazaraError("Index must be 0 for non-color attachments");
return false;
}
if (attachmentPoint == nzAttachmentPoint_Stencil)
{
NazaraError("Targeting stencil-only textures is not supported");
return false;
}
unsigned int depthStencilIndex = attachmentIndex[nzAttachmentPoint_DepthStencil];
if (attachmentPoint == nzAttachmentPoint_Stencil && m_impl->attachements.size() > depthStencilIndex &&
m_impl->attachements[depthStencilIndex].isUsed)
{
NazaraError("Stencil target already attached by DepthStencil attachment");
return false;
}
if (!texture || !texture->IsValid())
{
NazaraError("Invalid texture");
return false;
}
if (texture->GetWidth() < m_impl->width || texture->GetHeight() < m_impl->height)
{
NazaraError("Texture cannot be smaller than render texture");
return false;
}
unsigned int depth = (texture->GetType() == nzImageType_Cubemap) ? 6 : texture->GetDepth();
if (z >= depth)
{
NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(depth) + ')');
return false;
}
if (texture->GetRenderTexture() != nullptr)
{
NazaraError("Texture already used by another render texture");
return false;
}
if (formatTypeToAttachment[NzPixelFormat::GetType(texture->GetFormat())] != attachmentPoint)
{
NazaraError("Pixel format type does not match attachment point type");
return false;
}
#endif
if (!Lock())
{
NazaraError("Failed to lock render texture");
return false;
}
// Détachement de l'attache précédente (Si il y a)
Detach(attachmentPoint, index);
switch (texture->GetType())
{
case nzImageType_1D:
glFramebufferTexture1D(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, GL_TEXTURE_1D, texture->GetOpenGLID(), 0);
break;
case nzImageType_1D_Array:
case nzImageType_2D_Array:
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, texture->GetOpenGLID(), 0, z);
break;
case nzImageType_2D:
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, NzOpenGL::TextureTarget[texture->GetType()], texture->GetOpenGLID(), 0);
break;
case nzImageType_3D:
glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, GL_TEXTURE_3D, texture->GetOpenGLID(), 0, z);
break;
case nzImageType_Cubemap:
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, NzOpenGL::CubemapFace[z], texture->GetOpenGLID(), 0);
break;
}
Unlock();
unsigned int minSize = attachmentIndex[attachmentPoint]+index+1;
if (m_impl->attachements.size() < minSize)
m_impl->attachements.resize(minSize);
Attachment& attachment = m_impl->attachements[minSize-1];
attachment.isBuffer = true;
attachment.isUsed = true;
attachment.texture = texture;
texture->AddResourceListener(this);
texture->SetRenderTexture(this);
m_impl->checked = false;
m_impl->drawBuffersUpdated = false;
return true;
}
bool NzRenderTexture::Create(unsigned int width, unsigned int height, bool lock)
{
if (!IsSupported())
{
NazaraError("Render textures not supported");
return false;
}
Destroy();
#if NAZARA_RENDERER_SAFE
if (width == 0)
{
NazaraError("Width must be at least 1 (0)");
return false;
}
if (height == 0)
{
NazaraError("Height must be at least 1 (0)");
return false;
}
if (NzContext::GetCurrent() == nullptr)
{
NazaraError("No active context");
return false;
}
#endif
NzRenderTextureImpl* impl = new NzRenderTextureImpl;
impl->width = width;
impl->height = height;
impl->context = NzContext::GetCurrent();
impl->context->AddResourceListener(this);
impl->fbo = 0;
glGenFramebuffers(1, &impl->fbo);
if (!impl->fbo)
{
NazaraError("Failed to create framebuffer");
delete impl;
return false;
}
m_impl = impl;
if (lock && !Lock())
{
NazaraError("Failed to lock render texture");
delete impl;
m_impl = nullptr;
return false;
}
return true;
}
void NzRenderTexture::Destroy()
{
if (m_impl)
{
#if NAZARA_RENDERER_SAFE
if (NzContext::GetCurrent() != m_impl->context)
{
NazaraError("RenderTexture can only be used with it's creation context");
return;
}
#endif
m_impl->context->RemoveResourceListener(this);
for (Attachment& attachment : m_impl->attachements)
{
if (attachment.isUsed)
{
if (attachment.isBuffer)
glDeleteRenderbuffers(1, &attachment.buffer);
else
{
attachment.texture->RemoveResourceListener(this);
attachment.texture->SetRenderTexture(nullptr);
}
}
}
glDeleteFramebuffers(1, &m_impl->fbo);
delete m_impl;
m_impl = nullptr;
}
}
void NzRenderTexture::Detach(nzAttachmentPoint attachmentPoint, nzUInt8 index)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Render texture not created");
return;
}
if (attachmentPoint != nzAttachmentPoint_Color && index > 0)
{
NazaraError("Index must be 0 for non-color attachments");
return;
}
#endif
unsigned int attachIndex = attachmentIndex[attachmentPoint]+index;
if (attachIndex >= m_impl->attachements.size())
return;
Attachment& attachement = m_impl->attachements[attachIndex];
if (!attachement.isUsed)
return;
if (!Lock())
{
NazaraError("Failed to lock render texture");
return;
}
attachement.isUsed = false;
if (attachement.isBuffer)
{
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, GL_RENDERBUFFER, 0);
glDeleteRenderbuffers(1, &attachement.buffer);
}
else
{
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, 0, 0);
attachement.texture->RemoveResourceListener(this);
attachement.texture->SetRenderTexture(nullptr);
}
Unlock();
m_impl->checked = false;
m_impl->drawBuffersUpdated = false;
}
unsigned int NzRenderTexture::GetHeight() const
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Render texture not created");
return 0;
}
#endif
return m_impl->height;
}
NzRenderTargetParameters NzRenderTexture::GetParameters() const
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Render texture not created");
return NzRenderTargetParameters();
}
#endif
return NzRenderTargetParameters();
}
unsigned int NzRenderTexture::GetWidth() const
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Render texture not created");
return 0;
}
#endif
return m_impl->width;
}
bool NzRenderTexture::IsComplete() const
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Render texture not created");
return false;
}
#endif
if (!m_impl->checked)
{
if (!Lock())
{
NazaraError("Failed to lock render texture");
return false;
}
GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
Unlock();
m_impl->complete = false;
switch (status)
{
case GL_FRAMEBUFFER_COMPLETE:
m_impl->complete = true;
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
NazaraError("Incomplete attachment");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
NazaraInternalError("Incomplete draw buffer");
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
NazaraInternalError("Incomplete read buffer");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
NazaraError("Incomplete missing attachment");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
NazaraError("Incomplete multisample");
break;
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
NazaraError("Incomplete layer targets");
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
NazaraError("Render texture has unsupported attachments");
break;
default:
NazaraInternalError("Unknown error");
}
m_impl->checked = true;
}
return m_impl->complete;
}
bool NzRenderTexture::IsRenderable() const
{
return IsComplete();
}
bool NzRenderTexture::IsValid() const
{
return m_impl != nullptr;
}
bool NzRenderTexture::Lock() const
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Render texture not created");
return false;
}
if (NzContext::GetCurrent() != m_impl->context)
{
NazaraError("RenderTexture cannot be used with this context");
return false;
}
#endif
if (lockedLevel++ == 0)
{
GLint previous;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previous);
lockedPrevious = previous;
if (lockedPrevious != m_impl->fbo)
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_impl->fbo);
}
return true;
}
void NzRenderTexture::Unlock() const
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Render texture not created");
return;
}
if (NzContext::GetCurrent() != m_impl->context)
{
NazaraError("RenderTexture cannot be used with this context");
return;
}
if (lockedLevel == 0)
{
NazaraWarning("Unlock called on non-locked texture");
return;
}
#endif
if (--lockedLevel == 0 && lockedPrevious != m_impl->fbo) // Ici, il est important qu'un FBO soit débindé si l'ancien était 0
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, lockedPrevious);
}
bool NzRenderTexture::HasContext() const
{
return false;
}
bool NzRenderTexture::IsSupported()
{
return NzRenderer::HasCapability(nzRendererCap_RenderTexture);
}
bool NzRenderTexture::Activate()
{
#if NAZARA_RENDERER_SAFE
if (NzContext::GetCurrent() != m_impl->context)
{
NazaraError("RenderTexture cannot be used with this context");
return false;
}
#endif
if (!m_impl->drawBuffersUpdated)
{
m_impl->drawBuffers.clear();
m_impl->drawBuffers.reserve(m_impl->attachements.size());
for (unsigned int i = attachmentIndex[nzAttachmentPoint_Color]; i < m_impl->attachements.size(); ++i)
{
if (m_impl->attachements[i].isUsed)
m_impl->drawBuffers.push_back(GL_COLOR_ATTACHMENT0 + i - attachmentIndex[nzAttachmentPoint_Color]);
}
m_impl->drawBuffersUpdated = true;
}
glDrawBuffers(m_impl->drawBuffers.size(), &m_impl->drawBuffers[0]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_impl->fbo);
return true;
}
void NzRenderTexture::Desactivate()
{
#if NAZARA_RENDERER_SAFE
if (NzContext::GetCurrent() != m_impl->context)
{
NazaraError("RenderTexture cannot be used with this context");
return;
}
#endif
glFlush();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
void NzRenderTexture::OnResourceDestroy(const NzResource* resource, int index)
{
if (resource == m_impl->context)
// Notre context a été détruit, libérons la RenderTexture pour éviter un leak
Destroy();
else
{
// Sinon, c'est une texture
// La ressource n'est plus, du coup nous mettons à jour
Attachment& attachement = m_impl->attachements[index];
attachement.isUsed = false;
m_impl->checked = false;
m_impl->drawBuffersUpdated = false;
}
}

View File

@ -40,7 +40,7 @@ NzRenderWindow::NzRenderWindow(NzWindowHandle handle, const NzContextParameters&
NzRenderWindow::~NzRenderWindow() NzRenderWindow::~NzRenderWindow()
{ {
// Nécessaire si NzWindow::Destroy est appelé par son destructeur // Nécessaire si NzWindow::Destroy est appelé par son destructeur
OnWindowDestroying(); OnWindowDestroy();
} }
bool NzRenderWindow::CopyToImage(NzImage* image) bool NzRenderWindow::CopyToImage(NzImage* image)
@ -178,17 +178,6 @@ void NzRenderWindow::EnableVerticalSync(bool enabled)
NazaraError("No context"); NazaraError("No context");
} }
NzContextParameters NzRenderWindow::GetContextParameters() const
{
if (m_context)
return m_context->GetParameters();
else
{
NazaraError("Window not created/context not initialized");
return NzContextParameters();
}
}
unsigned int NzRenderWindow::GetHeight() const unsigned int NzRenderWindow::GetHeight() const
{ {
return NzWindow::GetHeight(); return NzWindow::GetHeight();
@ -213,14 +202,9 @@ unsigned int NzRenderWindow::GetWidth() const
return NzWindow::GetWidth(); return NzWindow::GetWidth();
} }
bool NzRenderWindow::HasContext() const bool NzRenderWindow::IsRenderable() const
{ {
return true; return m_impl != nullptr; // Si m_impl est valide, alors m_context l'est aussi
}
bool NzRenderWindow::IsValid() const
{
return m_impl != nullptr && m_context != nullptr;
} }
void NzRenderWindow::SetFramerateLimit(unsigned int limit) void NzRenderWindow::SetFramerateLimit(unsigned int limit)
@ -228,6 +212,22 @@ void NzRenderWindow::SetFramerateLimit(unsigned int limit)
m_framerateLimit = limit; m_framerateLimit = limit;
} }
NzContextParameters NzRenderWindow::GetContextParameters() const
{
if (m_context)
return m_context->GetParameters();
else
{
NazaraError("Window not created/context not initialized");
return NzContextParameters();
}
}
bool NzRenderWindow::HasContext() const
{
return true;
}
bool NzRenderWindow::Activate() bool NzRenderWindow::Activate()
{ {
if (m_context->SetActive(true)) if (m_context->SetActive(true))
@ -242,15 +242,6 @@ bool NzRenderWindow::Activate()
} }
} }
void NzRenderWindow::OnWindowDestroying()
{
if (m_context)
{
delete m_context;
m_context = nullptr;
}
}
bool NzRenderWindow::OnWindowCreated() bool NzRenderWindow::OnWindowCreated()
{ {
m_parameters.doubleBuffered = true; m_parameters.doubleBuffered = true;
@ -267,12 +258,19 @@ bool NzRenderWindow::OnWindowCreated()
EnableVerticalSync(false); EnableVerticalSync(false);
#if NAZARA_RENDERER_ACTIVATE_RENDERWINDOW_ON_CREATION
if (!SetActive(true)) // Les fenêtres s'activent à la création if (!SetActive(true)) // Les fenêtres s'activent à la création
NazaraWarning("Failed to activate window"); NazaraWarning("Failed to activate window");
#endif
m_clock.Restart(); m_clock.Restart();
return true; return true;
} }
void NzRenderWindow::OnWindowDestroy()
{
if (m_context)
{
delete m_context;
m_context = nullptr;
}
}

View File

@ -24,114 +24,6 @@
namespace namespace
{ {
const nzUInt8 attribIndex[] =
{
2, // nzElementUsage_Diffuse
1, // nzElementUsage_Normal
0, // nzElementUsage_Position
3, // nzElementUsage_Tangent
4 // nzElementUsage_TexCoord (Doit être le dernier de la liste car extensible)
};
const GLenum blendFunc[] =
{
GL_DST_ALPHA, // nzBlendFunc_DestAlpha
GL_DST_COLOR, // nzBlendFunc_DestColor
GL_SRC_ALPHA, // nzBlendFunc_SrcAlpha
GL_SRC_COLOR, // nzBlendFunc_SrcColor
GL_ONE_MINUS_DST_ALPHA, // nzBlendFunc_InvDestAlpha
GL_ONE_MINUS_DST_COLOR, // nzBlendFunc_InvDestColor
GL_ONE_MINUS_SRC_ALPHA, // nzBlendFunc_InvSrcAlpha
GL_ONE_MINUS_SRC_COLOR, // nzBlendFunc_InvSrcColor
GL_ONE, // nzBlendFunc_One
GL_ZERO // nzBlendFunc_Zero
};
const GLenum faceCullingMode[] =
{
GL_BACK, // nzFaceCulling_Back
GL_FRONT, // nzFaceCulling_Front
GL_FRONT_AND_BACK // nzFaceCulling_FrontAndBack
};
const GLenum faceFillingMode[] =
{
GL_POINT, // nzFaceFilling_Point
GL_LINE, // nzFaceFilling_Line
GL_FILL // nzFaceFilling_Fill
};
const GLenum openglPrimitive[] =
{
GL_LINES, // nzPrimitiveType_LineList,
GL_LINE_STRIP, // nzPrimitiveType_LineStrip,
GL_POINTS, // nzPrimitiveType_PointList,
GL_TRIANGLES, // nzPrimitiveType_TriangleList,
GL_TRIANGLE_STRIP, // nzPrimitiveType_TriangleStrip,
GL_TRIANGLE_FAN // nzPrimitiveType_TriangleFan
};
const nzUInt8 openglSize[] =
{
4, // nzElementType_Color
1, // nzElementType_Double1
2, // nzElementType_Double2
3, // nzElementType_Double3
4, // nzElementType_Double4
1, // nzElementType_Float1
2, // nzElementType_Float2
3, // nzElementType_Float3
4 // nzElementType_Float4
};
const GLenum openglType[] =
{
GL_UNSIGNED_BYTE, // nzElementType_Color
GL_DOUBLE, // nzElementType_Double1
GL_DOUBLE, // nzElementType_Double2
GL_DOUBLE, // nzElementType_Double3
GL_DOUBLE, // nzElementType_Double4
GL_FLOAT, // nzElementType_Float1
GL_FLOAT, // nzElementType_Float2
GL_FLOAT, // nzElementType_Float3
GL_FLOAT // nzElementType_Float4
};
const GLenum rendererComparison[] =
{
GL_ALWAYS, // nzRendererComparison_Always
GL_EQUAL, // nzRendererComparison_Equal
GL_GREATER, // nzRendererComparison_Greater
GL_GEQUAL, // nzRendererComparison_GreaterOrEqual
GL_LESS, // nzRendererComparison_Less
GL_LEQUAL, // nzRendererComparison_LessOrEqual
GL_NEVER // nzRendererComparison_Never
};
const GLenum rendererParameter[] =
{
GL_BLEND, // nzRendererParameter_Blend
GL_NONE, // nzRendererParameter_ColorWrite
GL_DEPTH_TEST, // nzRendererParameter_DepthTest
GL_NONE, // nzRendererParameter_DepthWrite
GL_CULL_FACE, // nzRendererParameter_FaceCulling
GL_STENCIL_TEST // nzRendererParameter_Stencil
};
const GLenum stencilOperation[] =
{
GL_DECR, // nzStencilOperation_Decrement
GL_DECR_WRAP, // nzStencilOperation_DecrementToSaturation
GL_INCR, // nzStencilOperation_Increment
GL_INCR_WRAP, // nzStencilOperation_IncrementToSaturation
GL_INVERT, // nzStencilOperation_Invert
GL_KEEP, // nzStencilOperation_Keep
GL_REPLACE, // nzStencilOperation_Replace
GL_ZERO // nzStencilOperation_Zero
};
///FIXME: Solution temporaire pour plus de facilité ///FIXME: Solution temporaire pour plus de facilité
enum nzMatrixCombination enum nzMatrixCombination
{ {
@ -227,7 +119,7 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int f
} }
if (s_indexBuffer->IsSequential()) if (s_indexBuffer->IsSequential())
glDrawArrays(openglPrimitive[primitive], s_indexBuffer->GetStartIndex(), s_indexBuffer->GetIndexCount()); glDrawArrays(NzOpenGL::PrimitiveType[primitive], s_indexBuffer->GetStartIndex(), s_indexBuffer->GetIndexCount());
else else
{ {
nzUInt8 indexSize = s_indexBuffer->GetIndexSize(); nzUInt8 indexSize = s_indexBuffer->GetIndexSize();
@ -252,7 +144,7 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int f
return; return;
} }
glDrawElements(openglPrimitive[primitive], indexCount, type, reinterpret_cast<const nzUInt8*>(s_indexBuffer->GetPointer()) + firstIndex*indexSize); glDrawElements(NzOpenGL::PrimitiveType[primitive], indexCount, type, reinterpret_cast<const nzUInt8*>(s_indexBuffer->GetPointer()) + firstIndex*indexSize);
} }
} }
@ -272,7 +164,7 @@ void NzRenderer::DrawPrimitives(nzPrimitiveType primitive, unsigned int firstVer
return; return;
} }
glDrawArrays(openglPrimitive[primitive], firstVertex, vertexCount); glDrawArrays(NzOpenGL::PrimitiveType[primitive], firstVertex, vertexCount);
} }
void NzRenderer::Enable(nzRendererParameter parameter, bool enable) void NzRenderer::Enable(nzRendererParameter parameter, bool enable)
@ -297,9 +189,9 @@ void NzRenderer::Enable(nzRendererParameter parameter, bool enable)
default: default:
if (enable) if (enable)
glEnable(rendererParameter[parameter]); glEnable(NzOpenGL::RendererParameter[parameter]);
else else
glDisable(rendererParameter[parameter]); glDisable(NzOpenGL::RendererParameter[parameter]);
break; break;
} }
@ -307,6 +199,7 @@ void NzRenderer::Enable(nzRendererParameter parameter, bool enable)
/* /*
NzMatrix4f NzRenderer::GetMatrix(nzMatrixCombination combination) NzMatrix4f NzRenderer::GetMatrix(nzMatrixCombination combination)
{ {
///FIXME: Duplication
switch (combination) switch (combination)
{ {
case nzMatrixCombination_ViewProj: case nzMatrixCombination_ViewProj:
@ -431,14 +324,16 @@ bool NzRenderer::Initialize()
s_vertexBuffer = nullptr; s_vertexBuffer = nullptr;
s_vertexDeclaration = nullptr; s_vertexDeclaration = nullptr;
// Récupération des capacités // Récupération des capacités d'OpenGL
s_capabilities[nzRendererCap_AnisotropicFilter] = NzOpenGL::IsSupported(NzOpenGL::AnisotropicFilter); s_capabilities[nzRendererCap_AnisotropicFilter] = NzOpenGL::IsSupported(nzOpenGLExtension_AnisotropicFilter);
s_capabilities[nzRendererCap_FP64] = NzOpenGL::IsSupported(NzOpenGL::FP64); s_capabilities[nzRendererCap_FP64] = NzOpenGL::IsSupported(nzOpenGLExtension_FP64);
s_capabilities[nzRendererCap_HardwareBuffer] = true; // Natif depuis OpenGL 1.5 s_capabilities[nzRendererCap_HardwareBuffer] = true; // Natif depuis OpenGL 1.5
s_capabilities[nzRendererCap_MultipleRenderTargets] = true; // Natif depuis OpenGL 2.0 // MultipleRenderTargets (Techniquement natif depuis OpenGL 2.0 mais inutile sans glBindFragDataLocation)
s_capabilities[nzRendererCap_MultipleRenderTargets] = (glBindFragDataLocation != nullptr);
s_capabilities[nzRendererCap_OcclusionQuery] = true; // Natif depuis OpenGL 1.5 s_capabilities[nzRendererCap_OcclusionQuery] = true; // Natif depuis OpenGL 1.5
s_capabilities[nzRendererCap_PixelBufferObject] = NzOpenGL::IsSupported(NzOpenGL::PixelBufferObject); s_capabilities[nzRendererCap_PixelBufferObject] = NzOpenGL::IsSupported(nzOpenGLExtension_PixelBufferObject);
s_capabilities[nzRendererCap_Texture3D] = NzOpenGL::IsSupported(NzOpenGL::Texture3D); s_capabilities[nzRendererCap_RenderTexture] = NzOpenGL::IsSupported(nzOpenGLExtension_FrameBufferObject);
s_capabilities[nzRendererCap_Texture3D] = true; // Natif depuis OpenGL 1.2
s_capabilities[nzRendererCap_TextureCubemap] = true; // Natif depuis OpenGL 1.3 s_capabilities[nzRendererCap_TextureCubemap] = true; // Natif depuis OpenGL 1.3
s_capabilities[nzRendererCap_TextureMulti] = true; // Natif depuis OpenGL 1.3 s_capabilities[nzRendererCap_TextureMulti] = true; // Natif depuis OpenGL 1.3
s_capabilities[nzRendererCap_TextureNPOT] = true; // Natif depuis OpenGL 2.0 s_capabilities[nzRendererCap_TextureNPOT] = true; // Natif depuis OpenGL 2.0
@ -458,7 +353,10 @@ bool NzRenderer::Initialize()
GLint maxDrawBuffers; GLint maxDrawBuffers;
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
s_maxRenderTarget = static_cast<unsigned int>(maxDrawBuffers); GLint maxColorAttachments;
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxColorAttachments);
s_maxRenderTarget = static_cast<unsigned int>(std::min(maxColorAttachments, maxDrawBuffers));
} }
else else
s_maxRenderTarget = 1; s_maxRenderTarget = 1;
@ -472,7 +370,7 @@ bool NzRenderer::Initialize()
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs); glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
// Impossible de binder plus de texcoords que d'attributes (en sachant qu'un certain nombre est déjà pris par les autres attributs) // Impossible de binder plus de texcoords que d'attributes (en sachant qu'un certain nombre est déjà pris par les autres attributs)
s_maxTextureUnit = static_cast<unsigned int>(std::min(maxTextureUnits, maxVertexAttribs-attribIndex[nzElementUsage_TexCoord])); s_maxTextureUnit = static_cast<unsigned int>(std::min(maxTextureUnits, maxVertexAttribs-NzOpenGL::AttributeIndex[nzElementUsage_TexCoord]));
} }
else else
s_maxTextureUnit = 1; s_maxTextureUnit = 1;
@ -499,7 +397,7 @@ void NzRenderer::SetBlendFunc(nzBlendFunc src, nzBlendFunc dest)
} }
#endif #endif
glBlendFunc(blendFunc[src], blendFunc[dest]); glBlendFunc(NzOpenGL::BlendFunc[src], NzOpenGL::BlendFunc[dest]);
} }
void NzRenderer::SetClearColor(const NzColor& color) void NzRenderer::SetClearColor(const NzColor& color)
@ -564,7 +462,7 @@ void NzRenderer::SetFaceCulling(nzFaceCulling cullingMode)
} }
#endif #endif
glCullFace(faceCullingMode[cullingMode]); glCullFace(NzOpenGL::FaceCulling[cullingMode]);
} }
void NzRenderer::SetFaceFilling(nzFaceFilling fillingMode) void NzRenderer::SetFaceFilling(nzFaceFilling fillingMode)
@ -577,7 +475,7 @@ void NzRenderer::SetFaceFilling(nzFaceFilling fillingMode)
} }
#endif #endif
glPolygonMode(GL_FRONT_AND_BACK, faceFillingMode[fillingMode]); glPolygonMode(GL_FRONT_AND_BACK, NzOpenGL::FaceFilling[fillingMode]);
} }
bool NzRenderer::SetIndexBuffer(const NzIndexBuffer* indexBuffer) bool NzRenderer::SetIndexBuffer(const NzIndexBuffer* indexBuffer)
@ -603,10 +501,6 @@ void NzRenderer::SetMatrix(nzMatrixType type, const NzMatrix4f& matrix)
{ {
s_matrix[type] = matrix; s_matrix[type] = matrix;
// Cas particulier, la matrice projection doit être inversée sur l'axe Y à cause des conventions d'OpenGL
if (type == nzMatrixType_Projection)
s_matrix[type] *= NzMatrix4f::Scale(NzVector3f(1.f, -1.f, 1.f));
// Invalidation des combinaisons // Invalidation des combinaisons
switch (type) switch (type)
{ {
@ -722,15 +616,15 @@ bool NzRenderer::SetTarget(NzRenderTarget* target)
if (s_target == target) if (s_target == target)
return true; return true;
if (s_target && !target->HasContext()) if (s_target && !s_target->HasContext())
s_target->Desactivate(); s_target->Desactivate();
if (target) if (target)
{ {
#if NAZARA_RENDERER_SAFE #if NAZARA_RENDERER_SAFE
if (!target->IsValid()) if (!target->IsRenderable())
{ {
NazaraError("Target not valid"); NazaraError("Target not renderable");
return false; return false;
} }
#endif #endif
@ -895,13 +789,13 @@ bool NzRenderer::EnsureStateUpdate()
if (!s_stencilFuncUpdated) if (!s_stencilFuncUpdated)
{ {
glStencilFunc(rendererComparison[s_stencilCompare], s_stencilReference, s_stencilMask); glStencilFunc(NzOpenGL::RendererComparison[s_stencilCompare], s_stencilReference, s_stencilMask);
s_stencilFuncUpdated = true; s_stencilFuncUpdated = true;
} }
if (!s_stencilOpUpdated) if (!s_stencilOpUpdated)
{ {
glStencilOp(stencilOperation[s_stencilFail], stencilOperation[s_stencilZFail], stencilOperation[s_stencilPass]); glStencilOp(NzOpenGL::StencilOperation[s_stencilFail], NzOpenGL::StencilOperation[s_stencilZFail], NzOpenGL::StencilOperation[s_stencilPass]);
s_stencilOpUpdated = true; s_stencilOpUpdated = true;
} }
@ -921,7 +815,7 @@ bool NzRenderer::EnsureStateUpdate()
} }
#endif #endif
static const bool vaoSupported = NzOpenGL::IsSupported(NzOpenGL::VertexArrayObject); static const bool vaoSupported = NzOpenGL::IsSupported(nzOpenGLExtension_VertexArrayObject);
bool update; bool update;
GLuint vao; GLuint vao;
@ -970,16 +864,16 @@ bool NzRenderer::EnsureStateUpdate()
if (element) if (element)
{ {
glEnableVertexAttribArray(attribIndex[i]); glEnableVertexAttribArray(NzOpenGL::AttributeIndex[i]);
glVertexAttribPointer(attribIndex[i], glVertexAttribPointer(NzOpenGL::AttributeIndex[i],
openglSize[element->type], NzVertexDeclaration::GetElementCount(element->type),
openglType[element->type], NzOpenGL::ElementType[element->type],
(element->type == nzElementType_Color) ? GL_TRUE : GL_FALSE, (element->type == nzElementType_Color) ? GL_TRUE : GL_FALSE,
stride, stride,
&buffer[element->offset]); &buffer[element->offset]);
} }
else else
glDisableVertexAttribArray(attribIndex[i]); glDisableVertexAttribArray(NzOpenGL::AttributeIndex[i]);
} }
if (s_indexBuffer) if (s_indexBuffer)

View File

@ -60,6 +60,7 @@ bool NzShader::Create(nzShaderLanguage language)
return false; return false;
} }
NotifyCreated();
return true; return true;
} }
@ -86,6 +87,8 @@ void NzShader::Destroy()
{ {
if (m_impl) if (m_impl)
{ {
NotifyDestroy();
m_impl->Destroy(); m_impl->Destroy();
delete m_impl; delete m_impl;
m_impl = nullptr; m_impl = nullptr;
@ -595,7 +598,7 @@ bool NzShader::IsLanguageSupported(nzShaderLanguage language)
switch (language) switch (language)
{ {
case nzShaderLanguage_Cg: case nzShaderLanguage_Cg:
return false; // ?? return false; //FIXME: ??
case nzShaderLanguage_GLSL: case nzShaderLanguage_GLSL:
return true; return true;

View File

@ -17,7 +17,7 @@ struct NzTextureImpl
nzImageType type; nzImageType type;
nzPixelFormat format; nzPixelFormat format;
nzUInt8 levelCount; nzUInt8 levelCount;
bool isTarget = false; NzRenderTexture* renderTexture = nullptr;
bool mipmapping = false; bool mipmapping = false;
bool mipmapsUpdated = true; bool mipmapsUpdated = true;
unsigned int depth; unsigned int depth;
@ -27,137 +27,18 @@ struct NzTextureImpl
namespace namespace
{ {
GLenum cubemapFace[] =
{
GL_TEXTURE_CUBE_MAP_POSITIVE_X, // nzCubemapFace_PositiveX
GL_TEXTURE_CUBE_MAP_NEGATIVE_X, // nzCubemapFace_NegativeX
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, // nzCubemapFace_PositiveY
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, // nzCubemapFace_NegativeY
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, // nzCubemapFace_PositiveZ
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z // nzCubemapFace_NegativeZ
};
GLenum openglTarget[] =
{
GL_TEXTURE_1D, // nzImageType_1D
GL_TEXTURE_1D_ARRAY, // nzImageType_1D_Array
GL_TEXTURE_2D, // nzImageType_2D
GL_TEXTURE_2D_ARRAY, // nzImageType_2D_Array
GL_TEXTURE_3D, // nzImageType_3D
GL_TEXTURE_CUBE_MAP // nzImageType_Cubemap
};
GLenum openglTargetBinding[] =
{
GL_TEXTURE_BINDING_1D, // nzImageType_1D
GL_TEXTURE_BINDING_1D_ARRAY, // nzImageType_1D
GL_TEXTURE_BINDING_2D, // nzImageType_2D
GL_TEXTURE_BINDING_3D, // nzImageType_3D
GL_TEXTURE_BINDING_CUBE_MAP // nzImageType_Cubemap
};
GLenum openglTargetProxy[] =
{
GL_PROXY_TEXTURE_1D, // nzImageType_1D
GL_PROXY_TEXTURE_1D_ARRAY, // nzImageType_1D_Array
GL_PROXY_TEXTURE_2D, // nzImageType_2D
GL_PROXY_TEXTURE_2D_ARRAY, // nzImageType_2D_Array
GL_PROXY_TEXTURE_3D, // nzImageType_3D
GL_PROXY_TEXTURE_CUBE_MAP // nzImageType_Cubemap
};
struct OpenGLFormat
{
GLint internalFormat;
GLenum dataFormat;
GLenum dataType;
};
bool GetOpenGLFormat(nzPixelFormat pixelFormat, OpenGLFormat* format)
{
switch (pixelFormat)
{
case nzPixelFormat_BGR8:
format->dataFormat = GL_BGR;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_RGB8;
return true;
case nzPixelFormat_BGRA8:
format->dataFormat = GL_BGRA;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_RGBA8;
return true;
case nzPixelFormat_DXT1:
format->dataFormat = GL_RGB;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
return true;
case nzPixelFormat_DXT3:
format->dataFormat = GL_RGBA;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
return true;
case nzPixelFormat_DXT5:
format->dataFormat = GL_RGBA;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
return true;
case nzPixelFormat_L8:
case nzPixelFormat_LA8:
NazaraError("Pixel format not supported");
return false;
case nzPixelFormat_RGB5A1:
format->dataFormat = GL_RGBA;
format->dataType = GL_UNSIGNED_SHORT_5_5_5_1;
format->internalFormat = GL_RGB5_A1;
return true;
case nzPixelFormat_RGB8:
format->dataFormat = GL_RGB;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_RGB8;
return true;
case nzPixelFormat_RGBA4:
format->dataFormat = GL_RGBA;
format->dataType = GL_UNSIGNED_SHORT_4_4_4_4;
format->internalFormat = GL_RGBA4;
return true;
case nzPixelFormat_RGBA8:
format->dataFormat = GL_RGBA;
format->dataType = GL_UNSIGNED_BYTE;
format->internalFormat = GL_RGBA8;
return true;
case nzPixelFormat_Undefined:
NazaraInternalError("Invalid pixel format");
return false;
}
NazaraError("Pixel format not handled");
return false;
}
bool CreateTexture(NzTextureImpl* impl, bool proxy) bool CreateTexture(NzTextureImpl* impl, bool proxy)
{ {
OpenGLFormat openGLFormat; NzOpenGL::Format openGLFormat;
if (!GetOpenGLFormat(impl->format, &openGLFormat)) if (!NzOpenGL::TranslateFormat(impl->format, &openGLFormat, NzOpenGL::FormatType_Texture))
{ {
NazaraError("Failed to get OpenGL format"); NazaraError("Format not supported by OpenGL");
return false; return false;
} }
GLenum target = (proxy) ? openglTargetProxy[impl->type] : openglTarget[impl->type]; GLenum target = (proxy) ? NzOpenGL::TextureTargetProxy[impl->type] : NzOpenGL::TextureTarget[impl->type];
GLint previous; GLint previous;
glGetIntegerv(openglTargetBinding[impl->type], &previous); glGetIntegerv(NzOpenGL::TextureTargetBinding[impl->type], &previous);
switch (impl->type) switch (impl->type)
{ {
case nzImageType_1D: case nzImageType_1D:
@ -234,7 +115,7 @@ namespace
unsigned int size = impl->width; // Les cubemaps ont une longueur et largeur identique unsigned int size = impl->width; // Les cubemaps ont une longueur et largeur identique
for (nzUInt8 level = 0; level < impl->levelCount; ++level) for (nzUInt8 level = 0; level < impl->levelCount; ++level)
{ {
for (GLenum face : cubemapFace) for (GLenum face : NzOpenGL::CubemapFace)
glTexImage2D(face, level, openGLFormat.internalFormat, size, size, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); glTexImage2D(face, level, openGLFormat.internalFormat, size, size, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr);
if (size > 1U) if (size > 1U)
@ -266,12 +147,12 @@ namespace
NzContext::EnsureContext(); NzContext::EnsureContext();
GLint previous; GLint previous;
glGetIntegerv(openglTargetBinding[impl->type], &previous); glGetIntegerv(NzOpenGL::TextureTargetBinding[impl->type], &previous);
lockedPrevious[impl->type] = static_cast<GLuint>(previous); lockedPrevious[impl->type] = static_cast<GLuint>(previous);
if (lockedPrevious[impl->type] != impl->id) if (lockedPrevious[impl->type] != impl->id)
glBindTexture(openglTarget[impl->type], impl->id); glBindTexture(NzOpenGL::TextureTarget[impl->type], impl->id);
} }
} }
@ -306,7 +187,7 @@ namespace
#endif #endif
if (--lockedLevel[impl->type] == 0 && lockedPrevious[impl->type] != impl->id) if (--lockedLevel[impl->type] == 0 && lockedPrevious[impl->type] != impl->id)
glBindTexture(openglTarget[impl->type], lockedPrevious[impl->type]); glBindTexture(NzOpenGL::TextureTarget[impl->type], lockedPrevious[impl->type]);
} }
} }
@ -334,42 +215,10 @@ NzTexture::~NzTexture()
Destroy(); Destroy();
} }
bool NzTexture::Bind() const
{
#if NAZARA_RENDERER_SAFE
if (lockedLevel[m_impl->type] > 0)
{
NazaraError("Cannot bind texture while a texture is locked");
return false;
}
#endif
glBindTexture(openglTarget[m_impl->type], m_impl->id);
if (m_impl->mipmapping && !m_impl->mipmapsUpdated)
{
glGenerateMipmap(openglTarget[m_impl->type]);
m_impl->mipmapsUpdated = true;
}
return true;
}
bool NzTexture::Create(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth, nzUInt8 levelCount, bool lock) bool NzTexture::Create(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth, nzUInt8 levelCount, bool lock)
{ {
#if NAZARA_RENDERER_SAFE
if (m_impl && m_impl->isTarget)
{
NazaraError("Texture is a target, it cannot be recreated");
return false;
}
#endif
Destroy(); Destroy();
if (width == 0 || height == 0 || depth == 0)
return true;
#if NAZARA_RENDERER_SAFE #if NAZARA_RENDERER_SAFE
if (!IsTypeSupported(type)) if (!IsTypeSupported(type))
{ {
@ -389,6 +238,24 @@ bool NzTexture::Create(nzImageType type, nzPixelFormat format, unsigned int widt
return false; return false;
} }
if (width == 0)
{
NazaraError("Width must be at least 1 (0)");
return false;
}
if (height == 0)
{
NazaraError("Height must be at least 1 (0)");
return false;
}
if (depth == 0)
{
NazaraError("Depth must be at least 1 (0)");
return false;
}
switch (type) switch (type)
{ {
case nzImageType_1D: case nzImageType_1D:
@ -491,6 +358,7 @@ bool NzTexture::Create(nzImageType type, nzPixelFormat format, unsigned int widt
if (!lock) if (!lock)
UnlockTexture(impl); UnlockTexture(impl);
NotifyCreated();
return true; return true;
} }
@ -498,13 +366,7 @@ void NzTexture::Destroy()
{ {
if (m_impl) if (m_impl)
{ {
#if NAZARA_RENDERER_SAFE NotifyDestroy();
if (m_impl->isTarget)
{
NazaraError("Texture is a target, it cannot be destroyed");
return;
}
#endif
NzContext::EnsureContext(); NzContext::EnsureContext();
@ -530,8 +392,8 @@ bool NzTexture::Download(NzImage* image) const
} }
#endif #endif
OpenGLFormat format; NzOpenGL::Format format;
if (!GetOpenGLFormat(m_impl->format, &format)) if (!NzOpenGL::TranslateFormat(m_impl->format, &format, NzOpenGL::FormatType_Texture))
{ {
NazaraError("Failed to get OpenGL format"); NazaraError("Failed to get OpenGL format");
return false; return false;
@ -552,7 +414,7 @@ bool NzTexture::Download(NzImage* image) const
// Téléchargement... // Téléchargement...
for (nzUInt8 level = 0; level < m_impl->levelCount; ++level) for (nzUInt8 level = 0; level < m_impl->levelCount; ++level)
{ {
glGetTexImage(openglTarget[m_impl->type], level, format.dataFormat, format.dataType, image->GetPixels(level)); glGetTexImage(NzOpenGL::TextureTarget[m_impl->type], level, format.dataFormat, format.dataType, image->GetPixels(level));
if (width > 1) if (width > 1)
width >>= 1; width >>= 1;
@ -610,7 +472,7 @@ unsigned int NzTexture::GetAnisotropyLevel() const
} }
#endif #endif
if (!NzOpenGL::IsSupported(NzOpenGL::AnisotropicFilter)) if (!NzOpenGL::IsSupported(nzOpenGLExtension_AnisotropicFilter))
return 1; return 1;
LockTexture(m_impl); LockTexture(m_impl);
@ -806,7 +668,7 @@ bool NzTexture::IsTarget() const
} }
#endif #endif
return m_impl->isTarget; return m_impl->renderTexture != nullptr;
} }
bool NzTexture::IsValid() const bool NzTexture::IsValid() const
@ -937,7 +799,7 @@ bool NzTexture::SetAnisotropyLevel(unsigned int anistropyLevel)
} }
#endif #endif
if (!NzOpenGL::IsSupported(NzOpenGL::AnisotropicFilter) && anistropyLevel > 1) if (anistropyLevel > 1 && !NzOpenGL::IsSupported(nzOpenGLExtension_AnisotropicFilter))
{ {
NazaraError("Anisotropic filter not supported"); NazaraError("Anisotropic filter not supported");
return false; return false;
@ -970,7 +832,7 @@ bool NzTexture::SetFilterMode(nzTextureFilter filter)
LockTexture(m_impl); LockTexture(m_impl);
GLenum target = openglTarget[m_impl->type]; GLenum target = NzOpenGL::TextureTarget[m_impl->type];
switch (filter) switch (filter)
{ {
case nzTextureFilter_Bilinear: case nzTextureFilter_Bilinear:
@ -1028,8 +890,8 @@ bool NzTexture::SetMipmapRange(nzUInt8 minLevel, nzUInt8 maxLevel)
#endif #endif
LockTexture(m_impl); LockTexture(m_impl);
glTexParameteri(openglTarget[m_impl->type], GL_TEXTURE_BASE_LEVEL, minLevel); glTexParameteri(NzOpenGL::TextureTarget[m_impl->type], GL_TEXTURE_BASE_LEVEL, minLevel);
glTexParameteri(openglTarget[m_impl->type], GL_TEXTURE_MAX_LEVEL, std::min(m_impl->levelCount, maxLevel)); glTexParameteri(NzOpenGL::TextureTarget[m_impl->type], GL_TEXTURE_MAX_LEVEL, std::min(m_impl->levelCount, maxLevel));
UnlockTexture(m_impl); UnlockTexture(m_impl);
return true; return true;
@ -1063,7 +925,7 @@ bool NzTexture::SetWrapMode(nzTextureWrap wrap)
LockTexture(m_impl); LockTexture(m_impl);
GLenum target = openglTarget[m_impl->type]; GLenum target = NzOpenGL::TextureTarget[m_impl->type];
switch (m_impl->type) switch (m_impl->type)
{ {
// Notez l'absence de "break" ici // Notez l'absence de "break" ici
@ -1197,7 +1059,7 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int
return false; return false;
} }
if (m_impl->isTarget) if (m_impl->renderTexture)
{ {
NazaraError("Texture is a target, it cannot be updated"); NazaraError("Texture is a target, it cannot be updated");
return false; return false;
@ -1244,8 +1106,8 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int
} }
#endif #endif
OpenGLFormat format; NzOpenGL::Format format;
if (!GetOpenGLFormat(m_impl->format, &format)) if (!NzOpenGL::TranslateFormat(m_impl->format, &format, NzOpenGL::FormatType_Texture))
{ {
NazaraError("Failed to get OpenGL format"); NazaraError("Failed to get OpenGL format");
return false; return false;
@ -1272,12 +1134,12 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int
case nzImageType_1D_Array: case nzImageType_1D_Array:
case nzImageType_2D: case nzImageType_2D:
glTexSubImage2D(openglTarget[m_impl->type], level, rect.x, height-rect.height-rect.y, rect.width, rect.height, format.dataFormat, format.dataType, mirrored.GetConstPixels()); glTexSubImage2D(NzOpenGL::TextureTarget[m_impl->type], level, rect.x, height-rect.height-rect.y, rect.width, rect.height, format.dataFormat, format.dataType, mirrored.GetConstPixels());
break; break;
case nzImageType_2D_Array: case nzImageType_2D_Array:
case nzImageType_3D: case nzImageType_3D:
glTexSubImage3D(openglTarget[m_impl->type], level, rect.x, height-rect.height-rect.y, z, rect.width, rect.height, 1, format.dataFormat, format.dataType, mirrored.GetConstPixels()); glTexSubImage3D(NzOpenGL::TextureTarget[m_impl->type], level, rect.x, height-rect.height-rect.y, z, rect.width, rect.height, 1, format.dataFormat, format.dataType, mirrored.GetConstPixels());
break; break;
case nzImageType_Cubemap: case nzImageType_Cubemap:
@ -1298,7 +1160,7 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 leve
return false; return false;
} }
if (m_impl->isTarget) if (m_impl->renderTexture)
{ {
NazaraError("Texture is a target, it cannot be updated"); NazaraError("Texture is a target, it cannot be updated");
return false; return false;
@ -1341,8 +1203,8 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 leve
} }
#endif #endif
OpenGLFormat format; NzOpenGL::Format format;
if (!GetOpenGLFormat(m_impl->format, &format)) if (!NzOpenGL::TranslateFormat(m_impl->format, &format, NzOpenGL::FormatType_Texture))
{ {
NazaraError("Failed to get OpenGL format"); NazaraError("Failed to get OpenGL format");
return false; return false;
@ -1370,12 +1232,12 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 leve
case nzImageType_1D_Array: case nzImageType_1D_Array:
case nzImageType_2D: case nzImageType_2D:
glTexSubImage2D(openglTarget[m_impl->type], level, cube.x, height-cube.height-cube.y, cube.width, cube.height, format.dataFormat, format.dataType, mirrored); glTexSubImage2D(NzOpenGL::TextureTarget[m_impl->type], level, cube.x, height-cube.height-cube.y, cube.width, cube.height, format.dataFormat, format.dataType, mirrored);
break; break;
case nzImageType_2D_Array: case nzImageType_2D_Array:
case nzImageType_3D: case nzImageType_3D:
glTexSubImage3D(openglTarget[m_impl->type], level, cube.x, height-cube.height-cube.y, cube.z, cube.width, cube.height, cube.depth, format.dataFormat, format.dataType, mirrored); glTexSubImage3D(NzOpenGL::TextureTarget[m_impl->type], level, cube.x, height-cube.height-cube.y, cube.z, cube.width, cube.height, cube.depth, format.dataFormat, format.dataType, mirrored);
break; break;
case nzImageType_Cubemap: case nzImageType_Cubemap:
@ -1455,7 +1317,7 @@ bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRe
return false; return false;
} }
if (m_impl->isTarget) if (m_impl->renderTexture)
{ {
NazaraError("Texture is a target, it cannot be updated"); NazaraError("Texture is a target, it cannot be updated");
return false; return false;
@ -1496,8 +1358,8 @@ bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRe
} }
#endif #endif
OpenGLFormat format; NzOpenGL::Format format;
if (!GetOpenGLFormat(m_impl->format, &format)) if (!NzOpenGL::TranslateFormat(m_impl->format, &format, NzOpenGL::FormatType_Texture))
{ {
NazaraError("Failed to get OpenGL format"); NazaraError("Failed to get OpenGL format");
return false; return false;
@ -1517,7 +1379,7 @@ bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRe
SetUnpackAlignement(bpp); SetUnpackAlignement(bpp);
LockTexture(m_impl); LockTexture(m_impl);
glTexSubImage2D(cubemapFace[face], level, rect.x, height-rect.height-rect.y, rect.width, rect.height, format.dataFormat, format.dataType, mirrored); glTexSubImage2D(NzOpenGL::CubemapFace[face], level, rect.x, height-rect.height-rect.y, rect.width, rect.height, format.dataFormat, format.dataType, mirrored);
UnlockTexture(m_impl); UnlockTexture(m_impl);
@ -1537,6 +1399,40 @@ void NzTexture::Unlock()
UnlockTexture(m_impl); UnlockTexture(m_impl);
} }
unsigned int NzTexture::GetOpenGLID() const
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Texture must be valid");
return 0;
}
#endif
return m_impl->id;
}
bool NzTexture::Prepare() const
{
#if NAZARA_RENDERER_SAFE
if (lockedLevel[m_impl->type] > 0)
{
NazaraError("Cannot bind texture while a texture is locked");
return false;
}
#endif
glBindTexture(NzOpenGL::TextureTarget[m_impl->type], m_impl->id);
if (m_impl->mipmapping && !m_impl->mipmapsUpdated)
{
glGenerateMipmap(NzOpenGL::TextureTarget[m_impl->type]);
m_impl->mipmapsUpdated = true;
}
return true;
}
unsigned int NzTexture::GetValidSize(unsigned int size) unsigned int NzTexture::GetValidSize(unsigned int size)
{ {
if (NzRenderer::HasCapability(nzRendererCap_TextureNPOT)) if (NzRenderer::HasCapability(nzRendererCap_TextureNPOT))
@ -1567,6 +1463,23 @@ bool NzTexture::IsFormatSupported(nzPixelFormat format)
case nzPixelFormat_RGBA4: case nzPixelFormat_RGBA4:
return true; return true;
// Formats de profondeur (Supportés avec les FBOs)
case nzPixelFormat_Depth16:
case nzPixelFormat_Depth24:
case nzPixelFormat_Depth32:
case nzPixelFormat_Depth24Stencil8:
{
static const bool supported = NzOpenGL::IsSupported(nzOpenGLExtension_FrameBufferObject);
return supported;
}
// Formats de stencil (Non supportés pour les textures)
case nzPixelFormat_Stencil1:
case nzPixelFormat_Stencil4:
case nzPixelFormat_Stencil8:
case nzPixelFormat_Stencil16:
return false;
// Dépréciés depuis OpenGL 3 (FIXME: Il doit bien exister des remplaçants ..) // Dépréciés depuis OpenGL 3 (FIXME: Il doit bien exister des remplaçants ..)
case nzPixelFormat_L8: case nzPixelFormat_L8:
case nzPixelFormat_LA8: case nzPixelFormat_LA8:
@ -1576,7 +1489,7 @@ bool NzTexture::IsFormatSupported(nzPixelFormat format)
case nzPixelFormat_DXT3: case nzPixelFormat_DXT3:
case nzPixelFormat_DXT5: case nzPixelFormat_DXT5:
{ {
static const bool supported = NzOpenGL::IsSupported(NzOpenGL::TextureCompression_s3tc); static const bool supported = NzOpenGL::IsSupported(nzOpenGLExtension_TextureCompression_s3tc);
return supported; return supported;
} }
@ -1607,7 +1520,7 @@ bool NzTexture::IsTypeSupported(nzImageType type)
case nzImageType_1D_Array: case nzImageType_1D_Array:
case nzImageType_2D_Array: case nzImageType_2D_Array:
{ {
static bool supported = NzOpenGL::IsSupported(NzOpenGL::TextureArray); static bool supported = NzOpenGL::IsSupported(nzOpenGLExtension_TextureArray);
return supported; return supported;
} }
} }
@ -1616,9 +1529,22 @@ bool NzTexture::IsTypeSupported(nzImageType type)
return false; return false;
} }
void NzTexture::SetTarget(bool isTarget) NzRenderTexture* NzTexture::GetRenderTexture() const
{ {
#if NAZARA_RENDERER_SAFE #ifdef NAZARA_DEBUG
if (!m_impl)
{
NazaraInternalError("Texture must be valid");
return nullptr;
}
#endif
return m_impl->renderTexture;
}
void NzTexture::SetRenderTexture(NzRenderTexture* renderTexture)
{
#ifdef NAZARA_DEBUG
if (!m_impl) if (!m_impl)
{ {
NazaraInternalError("Texture must be valid"); NazaraInternalError("Texture must be valid");
@ -1626,5 +1552,5 @@ void NzTexture::SetTarget(bool isTarget)
} }
#endif #endif
m_impl->isTarget = isTarget; m_impl->renderTexture = renderTexture;
} }

View File

@ -153,28 +153,19 @@ bool NzContextImpl::Create(NzContextParameters& parameters)
*attrib++ = WGL_CONTEXT_MINOR_VERSION_ARB; *attrib++ = WGL_CONTEXT_MINOR_VERSION_ARB;
*attrib++ = parameters.minorVersion; *attrib++ = parameters.minorVersion;
int flags = 0;
if (parameters.majorVersion >= 3) if (parameters.majorVersion >= 3)
{ {
*attrib++ = WGL_CONTEXT_PROFILE_MASK_ARB; *attrib++ = WGL_CONTEXT_PROFILE_MASK_ARB;
if (parameters.compatibilityProfile) *attrib++ = (parameters.compatibilityProfile) ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
*attrib++ = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
else
{
*attrib++ = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
}
} }
if (parameters.debugMode) if (parameters.debugMode)
flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
if (flags)
{ {
*attrib++ = WGL_CONTEXT_FLAGS_ARB; *attrib++ = WGL_CONTEXT_FLAGS_ARB;
*attrib++ = flags; *attrib++ = WGL_CONTEXT_DEBUG_BIT_ARB;
// Les contextes forward-compatible ne sont plus utilisés pour cette raison :
// http://www.opengl.org/discussion_boards/showthread.php/175052-Forward-compatible-vs-Core-profile
} }
*attrib++ = 0; *attrib++ = 0;
@ -210,13 +201,25 @@ bool NzContextImpl::Create(NzContextParameters& parameters)
void NzContextImpl::Destroy() void NzContextImpl::Destroy()
{ {
if (m_context) if (m_context)
{
if (wglGetCurrentContext() == m_context)
wglMakeCurrent(nullptr, nullptr);
wglDeleteContext(m_context); wglDeleteContext(m_context);
m_context = nullptr;
}
if (m_deviceContext) if (m_deviceContext)
{
ReleaseDC(m_window, m_deviceContext); ReleaseDC(m_window, m_deviceContext);
m_deviceContext = nullptr;
}
if (m_ownsWindow) if (m_ownsWindow)
{
DestroyWindow(m_window); DestroyWindow(m_window);
m_window = nullptr;
}
} }
void NzContextImpl::SwapBuffers() void NzContextImpl::SwapBuffers()

View File

@ -33,13 +33,13 @@ NzAnimation::~NzAnimation()
Destroy(); Destroy();
} }
unsigned int NzAnimation::AddSequence(const NzSequence& sequence) bool NzAnimation::AddSequence(const NzSequence& sequence)
{ {
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
if (!m_impl) if (!m_impl)
{ {
NazaraError("Animation not created"); NazaraError("Animation not created");
return 0; return false;
} }
#endif #endif
@ -52,7 +52,7 @@ unsigned int NzAnimation::AddSequence(const NzSequence& sequence)
if (it != m_impl->sequenceMap.end()) if (it != m_impl->sequenceMap.end())
{ {
NazaraError("Sequence name \"" + sequence.name + "\" is already used"); NazaraError("Sequence name \"" + sequence.name + "\" is already used");
return 0; return false;
} }
#endif #endif
@ -61,7 +61,7 @@ unsigned int NzAnimation::AddSequence(const NzSequence& sequence)
m_impl->sequences.push_back(sequence); m_impl->sequences.push_back(sequence);
return index; return true;
} }
bool NzAnimation::Create(nzAnimationType type, unsigned int frameCount) bool NzAnimation::Create(nzAnimationType type, unsigned int frameCount)
@ -86,6 +86,7 @@ bool NzAnimation::Create(nzAnimationType type, unsigned int frameCount)
m_impl->frameCount = frameCount; m_impl->frameCount = frameCount;
m_impl->type = type; m_impl->type = type;
NotifyCreated();
return true; return true;
} }
@ -93,6 +94,8 @@ void NzAnimation::Destroy()
{ {
if (m_impl) if (m_impl)
{ {
NotifyDestroy();
delete m_impl; delete m_impl;
m_impl = nullptr; m_impl = nullptr;
} }
@ -206,6 +209,28 @@ unsigned int NzAnimation::GetSequenceCount() const
return m_impl->sequences.size(); return m_impl->sequences.size();
} }
int NzAnimation::GetSequenceIndex(const NzString& sequenceName) const
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Animation not created");
return -1;
}
auto it = m_impl->sequenceMap.find(sequenceName);
if (it == m_impl->sequenceMap.end())
{
NazaraError("Sequence not found");
return -1;
}
return it->second;
#else
return m_impl->sequenceMap[sequenceName];
#endif
}
nzAnimationType NzAnimation::GetType() const nzAnimationType NzAnimation::GetType() const
{ {
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
@ -277,13 +302,13 @@ void NzAnimation::RemoveSequence(const NzString& identifier)
auto it = m_impl->sequenceMap.find(identifier); auto it = m_impl->sequenceMap.find(identifier);
if (it == m_impl->sequenceMap.end()) if (it == m_impl->sequenceMap.end())
{ {
NazaraError("SubMesh not found"); NazaraError("Sequence not found");
return; return;
} }
unsigned int index = it->second; int index = it->second;
#else #else
unsigned int index = m_impl->sequenceMap[identifier]; int index = m_impl->sequenceMap[identifier];
#endif #endif
auto it2 = m_impl->sequences.begin(); auto it2 = m_impl->sequences.begin();

View File

@ -113,14 +113,16 @@ bool NzBuffer::Create(unsigned int length, nzUInt8 typeSize, nzBufferStorage sto
m_storage = storage; m_storage = storage;
m_usage = usage; m_usage = usage;
// Si on arrive ici c'est que tout s'est bien passé. NotifyCreated();
return true; return true; // Si on arrive ici c'est que tout s'est bien passé.
} }
void NzBuffer::Destroy() void NzBuffer::Destroy()
{ {
if (m_impl) if (m_impl)
{ {
NotifyDestroy();
m_impl->Destroy(); m_impl->Destroy();
delete m_impl; delete m_impl;
m_impl = nullptr; m_impl = nullptr;

View File

@ -215,9 +215,6 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width,
{ {
ReleaseImage(); ReleaseImage();
if (width == 0 || height == 0 || depth == 0)
return true;
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
if (!NzPixelFormat::IsValid(format)) if (!NzPixelFormat::IsValid(format))
{ {
@ -225,6 +222,24 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width,
return false; return false;
} }
if (width == 0)
{
NazaraError("Width must be at least 1 (0)");
return false;
}
if (height == 0)
{
NazaraError("Height must be at least 1 (0)");
return false;
}
if (depth == 0)
{
NazaraError("Depth must be at least 1 (0)");
return false;
}
switch (type) switch (type)
{ {
case nzImageType_1D: case nzImageType_1D:
@ -315,11 +330,13 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width,
m_sharedImage = new SharedImage(1, type, format, levelCount, levels, width, height, depth); m_sharedImage = new SharedImage(1, type, format, levelCount, levels, width, height, depth);
NotifyCreated();
return true; return true;
} }
void NzImage::Destroy() void NzImage::Destroy()
{ {
NotifyDestroy();
ReleaseImage(); ReleaseImage();
} }

View File

@ -43,27 +43,6 @@ namespace
return false; return false;
} }
// Les fichiers MD2 sont en little endian
#if defined(NAZARA_BIG_ENDIAN)
NzByteSwap(&header.ident, sizeof(nzUInt32));
#endif
if (header.ident != md2Ident)
{
NazaraError("Invalid MD2 file");
return false;
}
#if defined(NAZARA_BIG_ENDIAN)
NzByteSwap(&header.version, sizeof(nzUInt32));
#endif
if (header.version != 8)
{
NazaraError("Bad version number (" + NzString::Number(header.version) + ')');
return false;
}
#if defined(NAZARA_BIG_ENDIAN) #if defined(NAZARA_BIG_ENDIAN)
NzByteSwap(&header.skinwidth, sizeof(nzUInt32)); NzByteSwap(&header.skinwidth, sizeof(nzUInt32));
NzByteSwap(&header.skinheight, sizeof(nzUInt32)); NzByteSwap(&header.skinheight, sizeof(nzUInt32));
@ -99,7 +78,7 @@ namespace
else else
animated = false; animated = false;
if (!mesh->Create((animated) ? nzAnimationType_Keyframe : nzAnimationType_Static)) // Ne devrait pas échouer if (!mesh->Create((animated) ? nzAnimationType_Keyframe : nzAnimationType_Static)) // Ne devrait jamais échouer
{ {
NazaraInternalError("Failed to create mesh"); NazaraInternalError("Failed to create mesh");
return false; return false;

View File

@ -71,8 +71,9 @@ bool NzMD2Mesh::Create(const md2_header& header, NzInputStream& stream, const Nz
md2_frame frame; md2_frame frame;
frame.vertices.resize(header.num_vertices); frame.vertices.resize(header.num_vertices);
// Pour que le modèle soit correctement aligné, on génère une matrice de rotation que nous appliquerons à chacune des vertices // Pour que le modèle soit correctement aligné, on génère un quaternion que nous appliquerons à chacune des vertices
NzMatrix4f rotationMatrix = NzMatrix4f::Rotate(NzEulerAnglesf(90.f, -90.f, 0.f)); NzQuaternionf rotationQuat = NzEulerAnglesf(-90.f, 90.f, 0.f);
//NzMatrix4f rotationMatrix = NzMatrix4f::Rotate(NzEulerAnglesf(-90.f, -90.f, 0.f));
unsigned int stride = s_declaration.GetStride(nzElementStream_VertexData); unsigned int stride = s_declaration.GetStride(nzElementStream_VertexData);
@ -94,7 +95,7 @@ bool NzMD2Mesh::Create(const md2_header& header, NzInputStream& stream, const Nz
NzByteSwap(&frame.translate.z, sizeof(float)); NzByteSwap(&frame.translate.z, sizeof(float));
#endif #endif
m_frames[i].normal = new nzUInt8[m_vertexCount]; // Nous stockons l'indice de la normale plutôt que la normale (gain d'espace) m_frames[i].normal = new nzUInt8[m_vertexCount]; // Nous stockons l'indice MD2 de la normale plutôt que la normale (gain d'espace)
m_frames[i].vertices = new NzVector3f[m_vertexCount]; m_frames[i].vertices = new NzVector3f[m_vertexCount];
NzVector3f max, min; NzVector3f max, min;
@ -104,12 +105,16 @@ bool NzMD2Mesh::Create(const md2_header& header, NzInputStream& stream, const Nz
{ {
const md2_vertex& vert = frame.vertices[triangles[t].vertices[v]]; const md2_vertex& vert = frame.vertices[triangles[t].vertices[v]];
NzVector3f vertex = rotationMatrix * NzVector3f(vert.x * frame.scale.x + frame.translate.x, vert.y * frame.scale.y + frame.translate.y, vert.z * frame.scale.z + frame.translate.z); NzVector3f vertex = rotationQuat * NzVector3f(vert.x * frame.scale.x + frame.translate.x, vert.y * frame.scale.y + frame.translate.y, vert.z * frame.scale.z + frame.translate.z);
max.MakeCeil(vertex);
min.MakeFloor(vertex);
m_frames[i].normal[t*3+v] = vert.n; // On fait en sorte d'avoir deux vertices de délimitation, définissant un rectangle dans l'espace
m_frames[i].vertices[t*3+v] = vertex; max.Maximize(vertex);
min.Minimize(vertex);
// Le MD2 ne définit pas ses vertices dans le bon ordre, il nous faut donc les ajouter dans l'ordre inverse
unsigned int index = m_vertexCount - (t*3 + v) - 1;
m_frames[i].normal[index] = vert.n;
m_frames[i].vertices[index] = vertex;
} }
} }
@ -128,8 +133,8 @@ bool NzMD2Mesh::Create(const md2_header& header, NzInputStream& stream, const Nz
return false; return false;
} }
// On avance jusqu'aux premières coordonnées de texture // On avance jusqu'aux dernières coordonnées de texture et on les définit dans l'ordre inverse
ptr += s_declaration.GetElement(nzElementStream_VertexData, nzElementUsage_TexCoord)->offset; ptr += s_declaration.GetElement(nzElementStream_VertexData, nzElementUsage_TexCoord)->offset + stride * (m_vertexCount-1);
for (unsigned int t = 0; t < header.num_tris; ++t) for (unsigned int t = 0; t < header.num_tris; ++t)
{ {
for (unsigned int v = 0; v < 3; ++v) for (unsigned int v = 0; v < 3; ++v)
@ -140,7 +145,7 @@ bool NzMD2Mesh::Create(const md2_header& header, NzInputStream& stream, const Nz
coords->x = texC.u / static_cast<float>(header.skinwidth); coords->x = texC.u / static_cast<float>(header.skinwidth);
coords->y = 1.f - texC.v / static_cast<float>(header.skinheight); coords->y = 1.f - texC.v / static_cast<float>(header.skinheight);
ptr += stride; ptr -= stride;
} }
} }

View File

@ -59,12 +59,6 @@ namespace
return false; return false;
} }
if (header.manufacturer != 0x0a)
{
NazaraError("Bad version number (" + NzString::Number(header.manufacturer) + ')');
return false;
}
#if defined(NAZARA_BIG_ENDIAN) #if defined(NAZARA_BIG_ENDIAN)
// Les fichiers PCX sont en little endian // Les fichiers PCX sont en little endian
NzByteSwap(&header.xmin, sizeof(nzUInt16)); NzByteSwap(&header.xmin, sizeof(nzUInt16));

View File

@ -31,8 +31,8 @@ bool NzMeshParams::IsValid() const
struct NzMeshImpl struct NzMeshImpl
{ {
std::map<NzString, nzUInt8> subMeshMap;
std::deque<NzString> skins; std::deque<NzString> skins;
std::map<NzString, unsigned int> subMeshMap;
std::vector<NzSubMesh*> subMeshes; std::vector<NzSubMesh*> subMeshes;
nzAnimationType animationType; nzAnimationType animationType;
NzAxisAlignedBox aabb; NzAxisAlignedBox aabb;
@ -44,19 +44,19 @@ NzMesh::~NzMesh()
Destroy(); Destroy();
} }
unsigned int NzMesh::AddSkin(const NzString& skin, bool setDefault) bool NzMesh::AddSkin(const NzString& skin, bool setDefault)
{ {
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
if (!m_impl) if (!m_impl)
{ {
NazaraError("Mesh not created"); NazaraError("Mesh not created");
return 0; return false;
} }
if (skin.IsEmpty()) if (skin.IsEmpty())
{ {
NazaraError("Skin is empty"); NazaraError("Skin is empty");
return 0; return false;
} }
#endif #endif
@ -65,71 +65,71 @@ unsigned int NzMesh::AddSkin(const NzString& skin, bool setDefault)
else else
m_impl->skins.push_back(skin); m_impl->skins.push_back(skin);
return m_impl->skins.size()-1; return true;
} }
nzUInt8 NzMesh::AddSubMesh(NzSubMesh* subMesh) bool NzMesh::AddSubMesh(NzSubMesh* subMesh)
{ {
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
if (!m_impl) if (!m_impl)
{ {
NazaraError("Mesh not created"); NazaraError("Mesh not created");
return 0; return false;
} }
if (!subMesh) if (!subMesh)
{ {
NazaraError("Invalid submesh"); NazaraError("Invalid submesh");
return 0; return false;
} }
#endif #endif
subMesh->AddResourceReference(); subMesh->AddResourceListener(this, m_impl->subMeshes.size());
m_impl->aabb.SetNull(); // On invalide l'AABB m_impl->aabb.SetNull(); // On invalide l'AABB
m_impl->subMeshes.push_back(subMesh); m_impl->subMeshes.push_back(subMesh);
return m_impl->subMeshes.size()-1; return true;
} }
nzUInt8 NzMesh::AddSubMesh(const NzString& identifier, NzSubMesh* subMesh) bool NzMesh::AddSubMesh(const NzString& identifier, NzSubMesh* subMesh)
{ {
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
if (!m_impl) if (!m_impl)
{ {
NazaraError("Mesh not created"); NazaraError("Mesh not created");
return 0; return false;
} }
if (identifier.IsEmpty()) if (identifier.IsEmpty())
{ {
NazaraError("Identifier is empty"); NazaraError("Identifier is empty");
return 0; return false;
} }
auto it = m_impl->subMeshMap.find(identifier); auto it = m_impl->subMeshMap.find(identifier);
if (it != m_impl->subMeshMap.end()) if (it != m_impl->subMeshMap.end())
{ {
NazaraError("SubMesh identifier \"" + identifier + "\" is already used"); NazaraError("SubMesh identifier \"" + identifier + "\" is already used");
return it->second; return false;
} }
if (!subMesh) if (!subMesh)
{ {
NazaraError("Invalid submesh"); NazaraError("Invalid submesh");
return 0; return false;
} }
#endif #endif
nzUInt8 index = m_impl->subMeshes.size(); int index = m_impl->subMeshes.size();
subMesh->AddResourceReference(); subMesh->AddResourceListener(this, index);
m_impl->aabb.SetNull(); // On invalide l'AABB m_impl->aabb.SetNull(); // On invalide l'AABB
m_impl->subMeshes.push_back(subMesh); m_impl->subMeshes.push_back(subMesh);
m_impl->subMeshMap[identifier] = index; m_impl->subMeshMap[identifier] = index;
return index; return true;
} }
void NzMesh::Animate(unsigned int frameA, unsigned int frameB, float interpolation) void NzMesh::Animate(unsigned int frameA, unsigned int frameB, float interpolation)
@ -180,6 +180,8 @@ bool NzMesh::Create(nzAnimationType type)
m_impl = new NzMeshImpl; m_impl = new NzMeshImpl;
m_impl->animationType = type; m_impl->animationType = type;
NotifyCreated();
return true; return true;
} }
@ -187,11 +189,13 @@ void NzMesh::Destroy()
{ {
if (m_impl) if (m_impl)
{ {
NotifyDestroy();
if (m_impl->animation) if (m_impl->animation)
m_impl->animation->RemoveResourceReference(); m_impl->animation->RemoveResourceListener(this);
for (NzSubMesh* subMesh : m_impl->subMeshes) for (NzSubMesh* subMesh : m_impl->subMeshes)
subMesh->RemoveResourceReference(); subMesh->RemoveResourceListener(this);
delete m_impl; delete m_impl;
m_impl = nullptr; m_impl = nullptr;
@ -316,7 +320,7 @@ NzSubMesh* NzMesh::GetSubMesh(const NzString& identifier)
#endif #endif
} }
NzSubMesh* NzMesh::GetSubMesh(nzUInt8 index) NzSubMesh* NzMesh::GetSubMesh(unsigned int index)
{ {
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
if (!m_impl) if (!m_impl)
@ -357,7 +361,7 @@ const NzSubMesh* NzMesh::GetSubMesh(const NzString& identifier) const
#endif #endif
} }
const NzSubMesh* NzMesh::GetSubMesh(nzUInt8 index) const const NzSubMesh* NzMesh::GetSubMesh(unsigned int index) const
{ {
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
if (!m_impl) if (!m_impl)
@ -376,7 +380,7 @@ const NzSubMesh* NzMesh::GetSubMesh(nzUInt8 index) const
return m_impl->subMeshes[index]; return m_impl->subMeshes[index];
} }
nzUInt8 NzMesh::GetSubMeshCount() const unsigned int NzMesh::GetSubMeshCount() const
{ {
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
if (!m_impl) if (!m_impl)
@ -389,6 +393,28 @@ nzUInt8 NzMesh::GetSubMeshCount() const
return m_impl->subMeshes.size(); return m_impl->subMeshes.size();
} }
int NzMesh::GetSubMeshIndex(const NzString& identifier) const
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Mesh not created");
return -1;
}
auto it = m_impl->subMeshMap.find(identifier);
if (it == m_impl->subMeshMap.end())
{
NazaraError("SubMesh not found");
return -1;
}
return it->second;
#else
return m_impl->subMeshMap[identifier];
#endif
}
unsigned int NzMesh::GetVertexCount() const unsigned int NzMesh::GetVertexCount() const
{ {
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
@ -458,7 +484,7 @@ bool NzMesh::HasSubMesh(const NzString& identifier) const
return m_impl->subMeshMap.find(identifier) != m_impl->subMeshMap.end(); return m_impl->subMeshMap.find(identifier) != m_impl->subMeshMap.end();
} }
bool NzMesh::HasSubMesh(nzUInt8 index) const bool NzMesh::HasSubMesh(unsigned int index) const
{ {
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
if (!m_impl) if (!m_impl)
@ -520,6 +546,7 @@ void NzMesh::RemoveSkin(unsigned int index)
} }
#endif #endif
// On accède à l'itérateur correspondant à l'entrée #index
auto it = m_impl->skins.begin(); auto it = m_impl->skins.begin();
std::advance(it, index); std::advance(it, index);
@ -547,15 +574,18 @@ void NzMesh::RemoveSubMesh(const NzString& identifier)
unsigned int index = m_impl->subMeshMap[identifier]; unsigned int index = m_impl->subMeshMap[identifier];
#endif #endif
// On déplace l'itérateur du début d'une distance de x
auto it2 = m_impl->subMeshes.begin(); auto it2 = m_impl->subMeshes.begin();
std::advance(it2, index); std::advance(it, index);
// On libère la ressource
(*it2)->RemoveResourceListener(this);
m_impl->subMeshes.erase(it2); m_impl->subMeshes.erase(it2);
m_impl->aabb.SetNull(); // On invalide l'AABB m_impl->aabb.SetNull(); // On invalide l'AABB
} }
void NzMesh::RemoveSubMesh(nzUInt8 index) void NzMesh::RemoveSubMesh(unsigned int index)
{ {
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
if (!m_impl) if (!m_impl)
@ -571,9 +601,12 @@ void NzMesh::RemoveSubMesh(nzUInt8 index)
} }
#endif #endif
// On déplace l'itérateur du début de x
auto it = m_impl->subMeshes.begin(); auto it = m_impl->subMeshes.begin();
std::advance(it, index); std::advance(it, index);
// On libère la ressource
(*it)->RemoveResourceListener(this);
m_impl->subMeshes.erase(it); m_impl->subMeshes.erase(it);
m_impl->aabb.SetNull(); // On invalide l'AABB m_impl->aabb.SetNull(); // On invalide l'AABB
@ -599,7 +632,7 @@ bool NzMesh::SetAnimation(const NzAnimation* animation)
return true; return true;
if (m_impl->animation) if (m_impl->animation)
m_impl->animation->RemoveResourceReference(); m_impl->animation->RemoveResourceListener(this);
if (animation) if (animation)
{ {
@ -611,13 +644,38 @@ bool NzMesh::SetAnimation(const NzAnimation* animation)
} }
#endif #endif
m_impl->animation = animation; animation->AddResourceListener(this);
m_impl->animation->AddResourceReference();
} }
else
m_impl->animation = nullptr; m_impl->animation = animation;
return true; return true;
} }
void NzMesh::OnResourceCreated(const NzResource* resource, int index)
{
NazaraUnused(index);
if (resource == m_impl->animation)
{
#if NAZARA_UTILITY_SAFE
if (m_impl->animation->GetType() != m_impl->animationType)
{
NazaraError("Animation's type must match mesh animation type");
m_impl->animation->RemoveResourceListener(this);
m_impl->animation = nullptr;
}
#endif
}
}
void NzMesh::OnResourceReleased(const NzResource* resource, int index)
{
if (resource == m_impl->animation)
SetAnimation(nullptr);
else
RemoveSubMesh(index);
}
NzMeshLoader::LoaderList NzMesh::s_loaders; NzMeshLoader::LoaderList NzMesh::s_loaders;

View File

@ -38,28 +38,27 @@ bool NzStaticMesh::Create(const NzVertexDeclaration* vertexDeclaration, NzVertex
#if NAZARA_UTILITY_SAFE #if NAZARA_UTILITY_SAFE
if (!vertexDeclaration) if (!vertexDeclaration)
{ {
NazaraError("Vertex declaration is null"); NazaraError("Invalid vertex declaration");
return false; return false;
} }
if (!vertexBuffer) if (!vertexBuffer)
{ {
NazaraError("Vertex buffer is null"); NazaraError("Invalid vertex buffer");
return false; return false;
} }
#endif #endif
if (indexBuffer) if (indexBuffer)
{ indexBuffer->AddResourceListener(this);
m_indexBuffer = indexBuffer; m_indexBuffer = indexBuffer;
m_indexBuffer->AddResourceReference();
}
m_vertexBuffer = vertexBuffer; m_vertexBuffer = vertexBuffer;
m_vertexBuffer->AddResourceReference(); m_vertexBuffer->AddResourceListener(this);
m_vertexDeclaration = vertexDeclaration; m_vertexDeclaration = vertexDeclaration;
m_vertexDeclaration->AddResourceReference(); m_vertexDeclaration->AddResourceListener(this);
return true; return true;
} }
@ -70,19 +69,19 @@ void NzStaticMesh::Destroy()
if (m_indexBuffer) if (m_indexBuffer)
{ {
m_indexBuffer->RemoveResourceReference(); m_indexBuffer->RemoveResourceListener(this);
m_indexBuffer = nullptr; m_indexBuffer = nullptr;
} }
if (m_vertexBuffer) if (m_vertexBuffer)
{ {
m_vertexBuffer->RemoveResourceReference(); m_vertexBuffer->RemoveResourceListener(this);
m_vertexBuffer = nullptr; m_vertexBuffer = nullptr;
} }
if (m_vertexDeclaration) if (m_vertexDeclaration)
{ {
m_vertexDeclaration->RemoveResourceReference(); m_vertexDeclaration->RemoveResourceListener(this);
m_vertexDeclaration = nullptr; m_vertexDeclaration = nullptr;
} }
} }
@ -184,3 +183,17 @@ void NzStaticMesh::AnimateImpl(unsigned int frameA, unsigned int frameB, float i
// Le safe mode est censé nous protéger de cet appel // Le safe mode est censé nous protéger de cet appel
NazaraError("Static mesh have no animation, please enable safe mode"); NazaraError("Static mesh have no animation, please enable safe mode");
} }
void NzStaticMesh::OnResourceReleased(const NzResource* resource, int index)
{
NazaraUnused(index);
if (resource == m_indexBuffer)
m_indexBuffer = nullptr;
else if (resource == m_vertexBuffer)
m_vertexBuffer = nullptr;
else if (resource == m_vertexDeclaration)
m_vertexDeclaration = nullptr;
else
NazaraInternalError("Not listening to " + NzString::Pointer(resource));
}

View File

@ -20,9 +20,22 @@
namespace namespace
{ {
const unsigned int size[] = const unsigned int elementCount[] =
{ {
sizeof(nzUInt32), // nzElementType_Color 4, // nzElementType_Color
1, // nzElementType_Double1
2, // nzElementType_Double2
3, // nzElementType_Double3
4, // nzElementType_Double4
1, // nzElementType_Float1
2, // nzElementType_Float2
3, // nzElementType_Float3
4 // nzElementType_Float4
};
const unsigned int elementSize[] =
{
4*sizeof(nzUInt8), // nzElementType_Color
1*sizeof(double), // nzElementType_Double1 1*sizeof(double), // nzElementType_Double1
2*sizeof(double), // nzElementType_Double2 2*sizeof(double), // nzElementType_Double2
3*sizeof(double), // nzElementType_Double3 3*sizeof(double), // nzElementType_Double3
@ -143,7 +156,7 @@ bool NzVertexDeclaration::Create(const NzVertexElement* elements, unsigned int e
if (impl->streamPos[current.stream] == -1) if (impl->streamPos[current.stream] == -1)
impl->streamPos[current.stream] = i; // Premier élément du stream (via le triage) impl->streamPos[current.stream] = i; // Premier élément du stream (via le triage)
impl->stride[current.stream] += size[current.type]; impl->stride[current.stream] += elementSize[current.type];
} }
#if NAZARA_UTILITY_FORCE_DECLARATION_STRIDE_MULTIPLE_OF_32 #if NAZARA_UTILITY_FORCE_DECLARATION_STRIDE_MULTIPLE_OF_32
@ -153,6 +166,7 @@ bool NzVertexDeclaration::Create(const NzVertexElement* elements, unsigned int e
m_sharedImpl = impl; m_sharedImpl = impl;
NotifyCreated();
return true; return true;
} }
@ -161,6 +175,8 @@ void NzVertexDeclaration::Destroy()
if (!m_sharedImpl) if (!m_sharedImpl)
return; return;
NotifyDestroy();
NazaraMutexLock(m_sharedImpl->mutex); NazaraMutexLock(m_sharedImpl->mutex);
bool freeSharedImpl = (--m_sharedImpl->refCount == 0); bool freeSharedImpl = (--m_sharedImpl->refCount == 0);
NazaraMutexUnlock(m_sharedImpl->mutex); NazaraMutexUnlock(m_sharedImpl->mutex);
@ -344,3 +360,13 @@ NzVertexDeclaration& NzVertexDeclaration::operator=(NzVertexDeclaration&& declar
return *this; return *this;
} }
unsigned int NzVertexDeclaration::GetElementCount(nzElementType type)
{
return elementCount[type];
}
unsigned int NzVertexDeclaration::GetElementSize(nzElementType type)
{
return elementSize[type];
}

View File

@ -107,7 +107,7 @@ bool NzWindow::Create(NzVideoMode mode, const NzString& title, nzUInt32 style)
{ {
if (!mode.IsFullscreenValid()) if (!mode.IsFullscreenValid())
{ {
NazaraWarning("Mode is not fullscreen valid"); NazaraWarning("Video mode is not fullscreen valid");
mode = NzVideoMode::GetFullscreenModes()[0]; mode = NzVideoMode::GetFullscreenModes()[0];
} }
@ -184,7 +184,7 @@ void NzWindow::Destroy()
{ {
if (m_impl) if (m_impl)
{ {
OnWindowDestroying(); OnWindowDestroy();
m_impl->Destroy(); m_impl->Destroy();
delete m_impl; delete m_impl;
@ -212,7 +212,7 @@ NzWindowHandle NzWindow::GetHandle() const
if (m_impl) if (m_impl)
return m_impl->GetHandle(); return m_impl->GetHandle();
else else
return reinterpret_cast<NzWindowHandle>(0); return static_cast<NzWindowHandle>(0);
} }
unsigned int NzWindow::GetHeight() const unsigned int NzWindow::GetHeight() const
@ -276,6 +276,11 @@ bool NzWindow::IsMinimized() const
return false; return false;
} }
bool NzWindow::IsValid() const
{
return m_impl != nullptr;
}
bool NzWindow::IsVisible() const bool NzWindow::IsVisible() const
{ {
if (m_impl) if (m_impl)
@ -483,15 +488,15 @@ bool NzWindow::WaitEvent(NzEvent* event)
#endif #endif
} }
void NzWindow::OnWindowDestroying()
{
}
bool NzWindow::OnWindowCreated() bool NzWindow::OnWindowCreated()
{ {
return true; return true;
} }
void NzWindow::OnWindowDestroy()
{
}
void NzWindow::IgnoreNextMouseEvent(int mouseX, int mouseY) const void NzWindow::IgnoreNextMouseEvent(int mouseX, int mouseY) const
{ {
if (m_impl) if (m_impl)