OpenGL application crashes some times - c++

I am working on a OpenGL application in C++ for some months now and never faced this problem before.
Coding in Visual Studio 2012 I can either run the application inside of the IDE or launch the executable file manually. In both cases I can choose between the debug and the release build. The following issue only appears when I start the release build executable myself. Otherwise everything works fine.
The application crashes sometimes when I add new forms into the scene on the fly. My operating system Windows 8 64bit lets me Debug the program from the crash dialog which indeed didn't help so much since it is a release build with less debug informations available at runtime, but it at least told me that the application crashes near the draw call glDrawTriangles(). There is only one draw call inside a loop in my code.
It drives me crazy that the crash only occurs irregular. Sometimes the application runs quite well for some minutes, sometimes it crashes immediately, and sometimes it runs some seconds. But I think is is important to know that the application only crashes right after new forms are inserted into the scene which I first generate in another thread and second create the OpenGL buffers in the main thread.
Here are the problem details that were shown in the Windows crash dialog. It seems like the driver of my videocard ATI Radeon 7870 crashes.
Problem signature:
Problem Event Name: APPCRASH
Application Name: Application.exe
Application Version: 0.0.0.0
Application Timestamp: 50f1491a
Fault Module Name: atioglxx.dll
Fault Module Version: 6.14.10.11931
Fault Module Timestamp: 50650037
Exception Code: c0000005
Exception Offset: 001108ef
OS Version: 6.2.9200.2.0.0.256.27
Locale ID: 1031
Additional Information 1: 5861
Additional Information 2: 5861822e1919d7c014bbb064c64908b2
Additional Information 3: dac6
Additional Information 4: dac6c2650fa14dd558bd9f448e23afd1
Read our privacy statement online:
http://go.microsoft.com/fwlink/?linkid=190175
If the online privacy statement is not available, please read our privacy statement offline:
C:\Windows\system32\en-US\erofflps.txt
What I've done so far is updating my video card drivers and debugging my application since I notices that the result were not reliable since the crash occurs spontaneously. There are many source files and to be honest I am not sure which is effecting the bug. It might be a file called terrain.cpp so I paste the code here.
#pragma once
#include "system.h"
#include "debug.h"
#include <vector>
#include <cstdlib>
#include <future>
using namespace std;
#include <GLEW/glew.h>
#include <SFML/OpenGL.hpp>
#include <SFML/Graphics/Image.hpp>
using namespace sf;
#include <GLM/glm.hpp>
#include <GLM/gtc/noise.hpp>
using namespace glm;
#include "settings.h"
#include "camera.h"
#include "form.h"
#include "transform.h"
#include "terrain.h"
#include "shader.h"
#include "movement.h"
typedef detail::tvec3<int> vec3i;
class ComponentTerrain : public Component
{
void Init()
{
auto wld = Global->Add<StorageTerrain>("terrain");
tasking = false;
Texture();
Listeners();
}
void Update()
{
auto wld = Global->Get<StorageTerrain>("terrain");
auto stg = Global->Get<StorageSettings>("settings");
auto cam = Global->Get<StorageCamera>("camera");
auto cks = Entity->Get<StorageChunk>();
int Distance = (int)(.5f * stg->Viewdistance / CHUNK_X / 2);
Debug::Info("Terrain chunk distance " + to_string(Distance));
for(int X = -Distance; X <= Distance; ++X)
for(int Z = -Distance; Z <= Distance; ++Z)
{
addChunk(X + (int)cam->Position.x / CHUNK_X, 0, Z + (int)cam->Position.z / CHUNK_Z);
}
for(auto chunk : wld->chunks)
{
auto chk = cks.find(chunk.second);
float distance = (float)vec3(chunk.first[0] * CHUNK_X - cam->Position.x, chunk.first[1] * CHUNK_Y - cam->Position.y, chunk.first[2] * CHUNK_Z - cam->Position.z).length();
if(distance > stg->Viewdistance)
deleteChunk(chunk.first[0], chunk.first[1], chunk.first[2]);
}
if(tasking)
{
if(task.wait_for(chrono::milliseconds(0)) == future_status::ready)
{
tasking = false;
Data data = task.get();
Buffers(data);
}
}
else
{
for(auto chunk : cks)
if(chunk.second->changed)
{
tasking = true;
chunk.second->changed = false;
task = async(launch::async, &ComponentTerrain::Mesh, this, Data(chunk.first));
break;
}
}
}
struct Data
{
Data() {}
Data(unsigned int id) : id(id) {}
unsigned int id;
vector<float> Vertices, Normals, Texcoords;
vector<int> Elements;
};
future<Data> task;
bool tasking;
Image texture;
void Listeners()
{
Event->Listen("SystemInitialized", [=]{
auto cam = Global->Get<StorageCamera>("camera");
cam->Position = vec3(0, CHUNK_Y, 0);
cam->Angles = vec2(0.75, -0.25);
});
Event->Listen("InputBindChunk", [=]{
addChunk(rand() % 5, 0, rand() % 5);
addChunk(rand() % 5, 0, rand() % 5);
addChunk(rand() % 5, 0, rand() % 5);
});
}
unsigned int getChunk(int X, int Y, int Z)
{
auto wld = Global->Get<StorageTerrain>("terrain");
array<int, 3> key = {X, Y, Z};
auto i = wld->chunks.find(key);
return (i != wld->chunks.end()) ? i->second : 0;
}
int addChunk(int X, int Y, int Z)
{
auto wld = Global->Get<StorageTerrain>("terrain");
auto shd = Global->Get<StorageShader>("shader"); // moved this line
unsigned int id = getChunk(X, Y, Z);
if(!id)
{
id = Entity->New();
Entity->Add<StorageChunk>(id);
auto frm = Entity->Add<StorageForm>(id); // moved this line
auto tsf = Entity->Add<StorageTransform>(id);
frm->Program = shd->Program; // moved this line
tsf->Position = vec3(X * CHUNK_X, Y * CHUNK_Y, Z * CHUNK_Z);
Generate(id, X, Y, Z);
array<int, 3> key = {X, Y, Z};
wld->chunks.insert(make_pair(key, id));
}
return id;
}
void deleteChunk(int X, int Y, int Z)
{
auto wld = Global->Get<StorageTerrain>("terrain");
unsigned int id = getChunk(X, Y, Z);
if(id < 1) return;
array<int, 3> key = {X, Y, Z};
wld->chunks.erase(key);
Entity->Delete<StorageChunk>(id);
Entity->Delete<StorageForm>(id);
Entity->Delete<StorageTransform>(id);
// free buffers
}
void Generate(unsigned int id, int X, int Y, int Z)
{
auto cnk = Entity->Get<StorageChunk>(id);
cnk->changed = true;
for(int x = 0; x < CHUNK_X; ++x) {
const float i = X + (float)x / CHUNK_X;
for(int z = 0; z < CHUNK_Z; ++z) {
const float j = Z + (float)z / CHUNK_Z;
double height_bias = 0.30;
double height_base = 0.50 * (simplex(0.2f * vec2(i, j)) + 1) / 2;
double height_fine = 0.20 * (simplex(1.5f * vec2(i, j)) + 1) / 2;
int height = (int)((height_bias + height_base + height_fine) * CHUNK_Y);
for(int y = 0; y < height; ++y) cnk->blocks[x][y][z] = true;
} }
}
#define TILES_U 4
#define TILES_V 4
Data Mesh(Data data)
{
auto cnk = Entity->Get<StorageChunk>(data.id);
auto *Vertices = &data.Vertices, *Normals = &data.Normals, *Texcoords = &data.Texcoords;
auto *Elements = &data.Elements;
const vec2 grid(1.f / TILES_U, 1.f / TILES_V);
int n = 0;
for(int X = 0; X < CHUNK_X; ++X)
for(int Y = 0; Y < CHUNK_Y; ++Y)
for(int Z = 0; Z < CHUNK_Z; ++Z)
if(cnk->blocks[X][Y][Z])
{
int Tile = Clamp(rand() % 2 + 1, 0, TILES_U * TILES_V - 1);
for(int dim = 0; dim < 3; ++dim) { int dir = -1; do {
vec3i neigh = Shift(dim, vec3i(dir, 0, 0)) + vec3i(X, Y, Z);
if(Inside(neigh, vec3i(0), vec3i(CHUNK_X, CHUNK_Y, CHUNK_Z) - 1))
if(cnk->blocks[neigh.x][neigh.y][neigh.z])
{ dir *= -1; continue; }
for(float i = 0; i <= 1; ++i)
for(float j = 0; j <= 1; ++j)
{
vec3 vertex = vec3(X, Y, Z) + floatify(Shift(dim, vec3i((dir+1)/2, i, j)));
Vertices->push_back(vertex.x); Vertices->push_back(vertex.y); Vertices->push_back(vertex.z);
}
vec3 normal = normalize(floatify(Shift(dim, vec3i(dir, 0, 0))));
for(int i = 0; i < 4; ++i)
{
Normals->push_back(normal.x); Normals->push_back(normal.y); Normals->push_back(normal.z);
}
vec2 position = (vec2(Tile % TILES_U, Tile / TILES_U) + .25f) * grid;
Texcoords->push_back(position.x); Texcoords->push_back(position.y);
Texcoords->push_back(position.x + grid.x/2); Texcoords->push_back(position.y);
Texcoords->push_back(position.x); Texcoords->push_back(position.y + grid.y/2);
Texcoords->push_back(position.x + grid.x/2); Texcoords->push_back(position.y + grid.y/2);
if(dir == -1) {
Elements->push_back(n+0); Elements->push_back(n+1); Elements->push_back(n+2);
Elements->push_back(n+1); Elements->push_back(n+3); Elements->push_back(n+2);
} else {
Elements->push_back(n+0); Elements->push_back(n+2); Elements->push_back(n+1);
Elements->push_back(n+1); Elements->push_back(n+2); Elements->push_back(n+3);
}
n += 4;
dir *= -1; } while(dir > 0); }
}
return data;
}
void Buffers(Data data)
{
auto frm = Entity->Get<StorageForm>(data.id);
glGenBuffers(1, &frm->Positions);
glBindBuffer(GL_ARRAY_BUFFER, frm->Positions);
glBufferData(GL_ARRAY_BUFFER, data.Vertices.size() * sizeof(float), &(data.Vertices[0]), GL_STATIC_DRAW);
glGenBuffers(1, &frm->Normals);
glBindBuffer(GL_ARRAY_BUFFER, frm->Normals);
glBufferData(GL_ARRAY_BUFFER, data.Normals.size() * sizeof(float), &(data.Normals[0]), GL_STATIC_DRAW);
glGenBuffers(1, &frm->Texcoords);
glBindBuffer(GL_ARRAY_BUFFER, frm->Texcoords);
glBufferData(GL_ARRAY_BUFFER, data.Texcoords.size() * sizeof(float), &(data.Texcoords[0]), GL_STATIC_DRAW);
glGenBuffers(1, &frm->Elements);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, frm->Elements);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.Elements.size() * sizeof(int), &data.Elements[0], GL_STATIC_DRAW);
glGenTextures(1, &frm->Texture);
glBindTexture(GL_TEXTURE_2D, frm->Texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.getSize().x, texture.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.getPixelsPtr());
glGenerateMipmap(GL_TEXTURE_2D);
}
void Texture()
{
Image image;
bool result = image.loadFromFile("forms/textures/terrain.png");
if(!result){ Debug::Fail("Terrain texture loading fail"); return; }
Vector2u size = Vector2u(image.getSize().x / TILES_U, image.getSize().y / TILES_V);
texture.create(image.getSize().x * 2, image.getSize().y * 2, Color());
for(int u = 0; u < TILES_U; ++u)
for(int v = 0; v < TILES_V; ++v)
{
Image tile, quarter;
tile.create(size.x, size.y, Color());
tile.copy(image, 0, 0, IntRect(size.x * u, size.y * v, size.x, size.y), true);
quarter.create(size.x, size.y, Color());
quarter.copy(tile, 0, 0, IntRect(size.x / 2, size.y / 2, size.x / 2, size.y / 2), true);
quarter.copy(tile, size.x / 2, 0, IntRect(0, size.y / 2, size.x / 2, size.y / 2), true);
quarter.copy(tile, 0, size.y / 2, IntRect(size.x / 2, 0, size.x / 2, size.y / 2), true);
quarter.copy(tile, size.x / 2, size.y / 2, IntRect(0, 0, size.x / 2, size.y / 2), true);
texture.copy(quarter, (u * 2 ) * size.x, (v * 2 ) * size.y, IntRect(0, 0, 0, 0), true);
texture.copy(quarter, (u * 2 + 1) * size.x, (v * 2 ) * size.y, IntRect(0, 0, 0, 0), true);
texture.copy(quarter, (u * 2 ) * size.x, (v * 2 + 1) * size.y, IntRect(0, 0, 0, 0), true);
texture.copy(quarter, (u * 2 + 1) * size.x, (v * 2 + 1) * size.y, IntRect(0, 0, 0, 0), true);
}
}
template <typename T>
inline T Clamp(T Value, T Min, T Max)
{
if(Value < Min) return Min;
if(Value > Max) return Max;
return Value;
}
bool Inside(vec3i Position, vec3i Min, vec3i Max)
{
if(Position.x < Min.x || Position.y < Min.y || Position.z < Min.z) return false;
if(Position.x > Max.x || Position.y > Max.y || Position.z > Max.z) return false;
return true;
}
inline vec3i Shift(int Dimension, vec3i Vector)
{
if (Dimension % 3 == 1) return vec3i(Vector.z, Vector.x, Vector.y);
else if (Dimension % 3 == 2) return vec3i(Vector.y, Vector.z, Vector.x);
else return Vector;
}
vec3 floatify(vec3i Value)
{
return vec3(Value.x, Value.y, Value.z);
}
};
However, you can find the whole code on Github.
Do you have any idea what could cause the crash or how to find the bug? Please let me know if you need more information and of which kind.
Thanks to #doomster I could find and fix the bug now.
The renderer component loops over a vector of forms to draw them. The asynchronous thread added new forms to that vector but their buffers were created later in the main thread after the generated vertices were returned. That means that drawing and form adding ran in parallel. The crash occurred when the renderer tried to render a form without any created buffers yet.
I inserted comments the code above to highlight the three lines I moved from addChunk() to Buffers() for fixing the issue. I sill do not know why only the release build executable crashed but that doesn't really matter any more.

There are two things I would verify here:
You are using a future<T>. I'm not sure, but if it runs in a different thread, that could have a negative impact on OpenGL which I have heard can behave sensitive to multithreaded use. Treat this as a rumour though, I'm not really sure about it, but trying to convert to single-threaded code is worth an attempt.
You can activate debug symbols in a release build, too. This should at least give you a usable backtrace when the crash happens. Actually, VS's Debug/Release settings are just default settings but without intrinsic meaning, so you can modify the Debug settings in steps until it matches the Release settings. That should give you a variant that fails while still being usable in a debugger.

Related

Low framerate with only map and minimap drawing (SFML)

I'm working on a small "game" like project as a practice, and I've managed to get my framerate down to not even 3 FPS. While the only thing that is being drawn is screen filling tiles and a minimap.
Now I've found that the problem is with the minimap, without it caps at 60 FPS. But unfortunately I'm not experienced enough to find out what the real problem is with it...
My draw function:
void StateIngame::draw()
{
m_gui.removeAllWidgets();
m_window.setView(m_view);
// Frame counter
float ct = m_clock.restart().asSeconds();
float fps = 1.f / ct;
m_time = ct;
char c[10];
sprintf(c, "%f", fps);
std::string fpsStr(c);
sf::String str(fpsStr);
auto fpsText = tgui::Label::create();
fpsText->setText(str);
fpsText->setTextSize(16);
fpsText->setPosition(15, 15);
m_gui.add(fpsText);
//////////////
// Draw map //
//////////////
int camOffsetX, camOffsetY;
int tileSize = m_map.getTileSize();
Tile tile;
sf::IntRect bounds = m_camera.getTileBounds(tileSize);
camOffsetX = m_camera.getTileOffset(tileSize).x;
camOffsetY = m_camera.getTileOffset(tileSize).y;
// Loop and draw each tile
// x and y = counters, tileX and tileY is the coordinates of the tile being drawn
for (int y = 0, tileY = bounds.top; y < bounds.height; y++, tileY++)
{
for (int x = 0, tileX = bounds.left; x < bounds.width; x++, tileX++)
{
try {
// Normal view
m_window.setView(m_view);
tile = m_map.getTile(tileX, tileY);
tile.render((x * tileSize) - camOffsetX, (y * tileSize) - camOffsetY, &m_window);
} catch (const std::out_of_range& oor)
{}
}
}
bounds = sf::IntRect(bounds.left - (bounds.width * 2), bounds.top - (bounds.height * 2), bounds.width * 4, bounds.height * 4);
for (int y = 0, tileY = bounds.top; y < bounds.height; y++, tileY++)
{
for (int x = 0, tileX = bounds.left; x < bounds.width; x++, tileX++)
{
try {
// Mini map
m_window.setView(m_minimap);
tile = m_map.getTile(tileX, tileY);
sf::RectangleShape miniTile(sf::Vector2f(4, 4));
miniTile.setFillColor(tile.m_color);
miniTile.setPosition((x * (tileSize / 4)), (y * (tileSize / 4)));
m_window.draw(miniTile);
} catch (const std::out_of_range& oor)
{}
}
}
// Gui
m_window.setView(m_view);
m_gui.draw();
}
The Tile class has a variable of type sf::Color which is set during map generating. This color is then used to draw the minimap instead of the 16x16 texture that is used for the map itself.
So when I leave out the minimap drawing, and only draw the map itself, it's more fluid than I could wish for...
Any help is appreciated!
You are generating the view completly new for every frame. Do this once on startup should be enought.

2D Diamond (isometric) map editor - Textures extended infinitely?

I'm currently developing a 2D isometric map editor.
I display entity(cube, player) which contains points and textures.
Each cubes are composed by 12 points.(12 points, but handled as 3 sides of 4 points when displayed by sfml(sf::VertexArray).
(I know I include some '.cpp' times to times, I have a problem with my IDE(visual studio) which I'm trying to resolve, please do not care about it.)
main.cpp
#pragma once
#include "globalfunctions.h" //global functions + main headers + class headers
int main() {
int mapSize = 0;
int cubeSize = 0;
cout << "Map size: "; cin >> mapSize; cout << endl;
cout << "Cube size: "; cin >> cubeSize; cout << endl;
int windowWidth = (mapSize * cubeSize) - (cubeSize * 2);
int windowHeight = ((mapSize * cubeSize) - (cubeSize * 2)) / 2;
renderWindow window(windowWidth, windowHeight, mapSize, cubeSize);
int nbMaxTextures = 9;
for (int t = 0; t < nbMaxTextures; t++) {
window.loadTexture("test", t);
}
window.run();
return EXIT_SUCCESS;
}
globalfunctions.h
#pragma once
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>
#include <math.h>
//#include <sstream>
#include <vector>
using namespace std;
sf::Vector2u isometricToCartesian(int i, int j, int cubeSize) {
sf::Vector2u carth;
carth.x = (j - i) * (cubeSize / 2);
carth.y = (j + i) * (cubeSize / 4);
return carth;
}
sf::Vector2u cartesianToIsometric(int x, int y, int cubeSize) {//TODO
sf::Vector2u iso;
iso.x = 0;
iso.y = 0;
return iso;
}
#include "entity.h"
#include "renderWindow.h"
renderWindow.h
#pragma once
class renderWindow {
public:
renderWindow(float WIDTH, float HEIGHT, int MAPSIZE, int CUBESIZE);
void run();
void loadTexture(sf::String folder, int numTexture);
//SETTERS
//...
//GETTERS
//...
private:
int mCurrentLayerID;
int mMapSize;
int mCubeSize;
int mSelectedTexture;
vector<entity> mMap;
sf::RenderWindow mWindow;
vector<sf::Texture> mTextures;
sf::Texture mMemoryTexture;
void processEvent();
void update(sf::Time deltaTime);
void render();
//CUBE ACTION-------------------------------------------
void addCube(int layerID, float x, float y);
entity& getCube(int ID);
entity& getCubeAt(float x, float y);
vector<sf::VertexArray> loadCube(int cubeID);//UPDATE DATA LIKE COORDINATES -> create/chnge the vertex
void drawCube(int cubeID);//draw the vertex
//VARIABLES
vector<sf::VertexArray> verticesSide1;
vector<sf::VertexArray> verticesSide2;
vector<sf::VertexArray> verticesSide3;
//CUBE ACTION-------------------------------------------
};
#include "renderWindow.cpp"
renderWindow.cpp
#pragma once
renderWindow::renderWindow(float WIDTH, float HEIGHT, int MAPSIZE, int CUBESIZE) : mWindow(sf::VideoMode(WIDTH, HEIGHT), "") {
mMapSize = MAPSIZE;
mCubeSize = CUBESIZE;
mSelectedTexture = 6;
mCurrentLayerID = -1;
int x = 0;
int y = 0;
//default layer
for (int j = 0; j < mMapSize; j++) {
for (int i = 0; i < mMapSize; i++) {
x = isometricToCartesian(i, j, mCubeSize).x;
y = isometricToCartesian(i, j, mCubeSize).y;
addCube(0, x, y);
}
}
for (int c = 0; c < mMap.size(); c++) {
verticesSide1.push_back(loadCube(c)[0]);
verticesSide2.push_back(loadCube(c)[1]);
verticesSide3.push_back(loadCube(c)[2]);
//then only do that when something the cube's coordinate changed
}
}
void renderWindow::run() {
sf::Clock clock;
sf::Time timeSinceLastUpdate = sf::Time::Zero;
sf::Time TimePerFrame = sf::seconds(1.f / 60.f);
while (mWindow.isOpen()) {
processEvent();
timeSinceLastUpdate += clock.restart();
while (timeSinceLastUpdate > TimePerFrame) {
timeSinceLastUpdate -= TimePerFrame;
processEvent();
update(TimePerFrame);
}
render();
}
}
void renderWindow::loadTexture(sf::String folder, int numTexture) {
if (mMemoryTexture.loadFromFile("textures/" + folder + "/" + to_string(numTexture) + ".jpg"))
mTextures.push_back(mMemoryTexture);
else
cout << "Texture n°" << numTexture << " as failed to load." << endl;
}
//SETTERS
//...
//GETTERS
//...
//PRIVATE METHODE
void renderWindow::processEvent() {
sf::Event event;
while (mWindow.pollEvent(event)) {
switch (event.type) {
case sf::Event::Closed:
mWindow.close();
break;
case sf::Event::KeyPressed:
if (event.key.code == sf::Keyboard::Escape)
mWindow.close();
break;
case sf::Event::MouseButtonPressed:
if (event.MouseButtonPressed == sf::Mouse::Left)
getCubeAt(event.mouseButton.x, event.mouseButton.y).setTexture(0, mSelectedTexture);//TEST
getCubeAt(event.mouseButton.x, event.mouseButton.y).setTexture(1, mSelectedTexture + 1);//TEST
getCubeAt(event.mouseButton.x, event.mouseButton.y).setTexture(2, mSelectedTexture + 2);//TEST
break;
/*case sf::Event::MouseMoved:
cout << "(" << event.mouseMove.x << ", " << event.mouseMove.y << ")" << endl;
break;*/
}
}
}
void renderWindow::update(sf::Time deltaTime) {
//REMEMBER: distance = speed * time
//MOVEMENT, ANIMATIONS ETC. ...
}
void renderWindow::render() {
mWindow.clear();
for (int c = 0; c < mMap.size(); c++) {
drawCube(c);
}
mWindow.display();
}
//CUBE ACTION-------------------------------------------
void renderWindow::addCube(int layerID, float x, float y) {
//Thoses make the code more readable:
int half_cubeSize = mCubeSize / 2;
int oneQuarter_cubeSize = mCubeSize / 4;
int twoQuarter_cubeSize = oneQuarter_cubeSize * 2;
int treeQuarter_cubeSize = oneQuarter_cubeSize * 3;
mCurrentLayerID = layerID;
entity dummy(mMap.size(), 0, layerID);
dummy.addPoint(12);
dummy.addTexture(6);
dummy.addTexture(7);
dummy.addTexture(8);
//SIDE 1------------------------------------------------
dummy.setPoint(0, x, y + oneQuarter_cubeSize);
dummy.setPoint(1, x + half_cubeSize, y + twoQuarter_cubeSize);
dummy.setPoint(2, x + half_cubeSize, y + mCubeSize);
dummy.setPoint(3, x, y + treeQuarter_cubeSize);
//SIDE 2------------------------------------------------
dummy.setPoint(4, x + half_cubeSize, y + twoQuarter_cubeSize);
dummy.setPoint(5, x + mCubeSize, y + oneQuarter_cubeSize);
dummy.setPoint(6, x + mCubeSize, y + treeQuarter_cubeSize);
dummy.setPoint(7, x + half_cubeSize, y + mCubeSize);
//SIDE 3------------------------------------------------
dummy.setPoint(8, x, y + oneQuarter_cubeSize);
dummy.setPoint(9, x + half_cubeSize, y);
dummy.setPoint(10, x + mCubeSize, y + oneQuarter_cubeSize);
dummy.setPoint(11, x + half_cubeSize, y + twoQuarter_cubeSize);
mMap.push_back(dummy);
}
entity& renderWindow::getCube(int ID) {
for (int c = 0; c < mMap.size(); c++) {
if (mMap[c].getID() == ID)
return mMap[c];
}
}
entity& renderWindow::getCubeAt(float x, float y) {//TO DO
return entity(-1, 0, 0);
}
vector<sf::VertexArray> renderWindow::loadCube(int cubeID) {
vector<sf::VertexArray> vertices;
vertices.push_back(sf::VertexArray());
vertices.push_back(sf::VertexArray());
vertices.push_back(sf::VertexArray());
vertices[0].setPrimitiveType(sf::Quads);
vertices[0].resize(4);
vertices[1].setPrimitiveType(sf::Quads);
vertices[1].resize(4);
vertices[2].setPrimitiveType(sf::Quads);
vertices[2].resize(4);
sf::Vector2f tv0 = sf::Vector2f(0, 0);
sf::Vector2f tv1 = sf::Vector2f(mCubeSize, 0);
sf::Vector2f tv2 = sf::Vector2f(mCubeSize, mCubeSize);
sf::Vector2f tv3 = sf::Vector2f(0, mCubeSize);
sf::Vector2f v0 = sf::Vector2f(getCube(cubeID).getPoint(0, 0), getCube(cubeID).getPoint(0, 1));
sf::Vector2f v1 = sf::Vector2f(getCube(cubeID).getPoint(1, 0), getCube(cubeID).getPoint(1, 1));
sf::Vector2f v2 = sf::Vector2f(getCube(cubeID).getPoint(2, 0), getCube(cubeID).getPoint(2, 1));
sf::Vector2f v3 = sf::Vector2f(getCube(cubeID).getPoint(3, 0), getCube(cubeID).getPoint(3, 1));
sf::Vector2f v4 = sf::Vector2f(getCube(cubeID).getPoint(4, 0), getCube(cubeID).getPoint(4, 1));
sf::Vector2f v5 = sf::Vector2f(getCube(cubeID).getPoint(5, 0), getCube(cubeID).getPoint(5, 1));
sf::Vector2f v6 = sf::Vector2f(getCube(cubeID).getPoint(6, 0), getCube(cubeID).getPoint(6, 1));
sf::Vector2f v7 = sf::Vector2f(getCube(cubeID).getPoint(7, 0), getCube(cubeID).getPoint(7, 1));
sf::Vector2f v8 = sf::Vector2f(getCube(cubeID).getPoint(8, 0), getCube(cubeID).getPoint(8, 1));
sf::Vector2f v9 = sf::Vector2f(getCube(cubeID).getPoint(9, 0), getCube(cubeID).getPoint(9, 1));
sf::Vector2f v10 = sf::Vector2f(getCube(cubeID).getPoint(10, 0), getCube(cubeID).getPoint(10, 1));
sf::Vector2f v11 = sf::Vector2f(getCube(cubeID).getPoint(11, 0), getCube(cubeID).getPoint(11, 1));
vertices[0][0] = sf::Vertex(v0, tv0);
vertices[0][1] = sf::Vertex(v1, tv1);
vertices[0][2] = sf::Vertex(v2, tv2);
vertices[0][3] = sf::Vertex(v3, tv3);
vertices[1][0] = sf::Vertex(v4, tv0);
vertices[1][1] = sf::Vertex(v5, tv1);
vertices[1][2] = sf::Vertex(v6, tv2);
vertices[1][3] = sf::Vertex(v7, tv3);
vertices[2][0] = sf::Vertex(v8, tv0);
vertices[2][1] = sf::Vertex(v9, tv1);
vertices[2][2] = sf::Vertex(v10, tv2);
vertices[2][3] = sf::Vertex(v11, tv3);
return vertices;
}
void renderWindow::drawCube(int cubeID) {
mWindow.draw(verticesSide1[cubeID], &mTextures[getCube(cubeID).getTexture(0)]);
mWindow.draw(verticesSide2[cubeID], &mTextures[getCube(cubeID).getTexture(1)]);
mWindow.draw(verticesSide3[cubeID], &mTextures[getCube(cubeID).getTexture(2)]);
}
//CUBE ACTION-------------------------------------------
entity.h
#pragma once
class entity {
public:
entity();
entity(int id, int type, int numlayer);
void addPoint(int nbPoints);
void addTexture(int numTexture);
//SETTERS
void setPoint(int numPoint, float x, float y);
void setTexture(int textureID, int numTexture);
//GETTERS
int getID();
float getPoint(int numPoint, int numIndex);//if numIndex = 0 -> x || if numIndex = 1 -> y
int getType();
int getNumLayer();
int getTexture(int numTexture);
private:
int mID;
int mType;
int mNumLayer;
vector<sf::Vector2u> mPoints;
vector<int> mTextures;
};
#include "entity.cpp"
entity.cpp
#pragma once
entity::entity() {
mID = 0;
mType = -1;
mNumLayer = 0;
}
entity::entity(int id, int type, int numlayer) {
mID = id;
mType = type;
mNumLayer = numlayer;
}
void entity::addPoint(int nbPoints) {
mPoints.clear();
int newSize = 0;
for (int p = 0; p < nbPoints; p++) {
newSize++;
}
mPoints = vector<sf::Vector2u>(newSize);
}
void entity::addTexture(int numTexture) {
mTextures.push_back(numTexture);
}
//SETTERS
void entity::setPoint(int numPoint, float x, float y) {
mPoints[numPoint].x = x;
mPoints[numPoint].y = y;
}
void entity::setTexture(int textureID, int numTexture) {
mTextures[textureID] = numTexture;
}
//GETTERS
int entity::getID() {
return mID;
}
float entity::getPoint(int numPoint, int numIndex) {
if (numIndex == 0)
return mPoints[numPoint].x;
else
return mPoints[numPoint].y;
}
int entity::getType() {
return mType;
}
int entity::getNumLayer() {
return mNumLayer;
}
int entity::getTexture(int numTexture) {
return mTextures[numTexture];
}
I've done a lot of test, too much, so I won't post them right now, but if you have any question, feel free to ask.
Here is the problem described in the title :
And here, screens with only one face displayed(in the same order in the code):
The only thing I don't understand is that a cube displayed alone work perfectly fine if you enter the coordinates manually. Even the extended ones. But the coordinates formula is ok... (I noticed that the cube n°50 for a 15x15 map with 64x64 cube display a rectangle 'infinite' in width)
If the texture is extended(maybe to the infinite), it suggest that the coordinates are continuously increasing somewhere ? Then, why the cubes are still well placed ?
Here are the assets(64*64 png) :
Directories : textures/test/
Not really an answer (as the code will be rewritten anyway) so few hints for the new code instead (some of them are already mentioned in the comments).
Tileset
In the final isometric engine use sprites. They are faster and support pixel art. For my purposes I use compilation of these two free to use tilesets (64x64):
outside tileset
medieval building tileset
Both are compatible. I compiled and edited them to suite the needs of my engine. So this is what I use (still work in progress):
White color 0x00FFFFFF means transparent. The sprite is not enough. I added info about the height of tile and rotations.
If you see first 4 tiles from upper left corner they all are the same thing rotated by 90 degrees. So all my tiles have index of 4 tiles (the 90 degree rotations) int rot[4]. This way I can rotate the whole map or just view. I compile the set so the rotations are next to each other. There are 3 options:
tile[ix].rot[]={ ix,ix,ix,ix }; where ix is tile without rotation (ground)
tile[ix].rot[]={ ix,ix+1,ix,ix+1 }; where ix is tile with 2 rotations (those 2 tiles with chunk of chopped tree in the middle right)
tile[ix].rot[]={ ix,ix+1,ix+2,ix+3 }; where ix is tile with 4 rotations (like the first tile)
The indexes are valid of coarse only for the first tile only, the others have the whole rot[] array rotated by 1 value from neighbor. Some rotations are invisible (see the wide trees) but the tile is still present to allow rotations.
The tile height is important for placing tiles while editing and also for automatic map generations.
I plan to add also A* map for each tile so I can use path finding or compute watter flows and more.
Map editor
I prefer 3D maps. with bigger resolution you need to properly select the viewed area for viewing to maximize performance. Also a good idea is to create hollow underground so the rendering is much faster (this can be also done virtually during rendering process without the need of updating map).
I recommend to code these features:
make ground hollow
make ground solid
random terrain (diamond & square)
filter out small holes and smooth edges (add the slope tiles to cubic ones)
tile editor
Apart from the obvious paint editor you should add also another features like:
floor <-> ceiling
left <-> right
front <-> back
divide large sprite into regular tiles
copy/merge/paste
adjust lighting after left <-> right mirror operation
They are really handy while compiling/editing tileset resources. As you can see my tileset has many of tiles not present in the source tilesets. They were created by these functions + some minor paint editing... The colored masks on the bottom of the tileset are used to mask out and properly combine parts of tiles to create the missing ones ... (you can take one side form one tile and other from other ...)
[Notes]
For more info/ideas have a look at some related Q/As:
Improving performance of click detection on a staggered column isometric grid
How to procedurally generate isometric map
And here my Standalone no install Win32 Demo:
demo v1.000
demo v1.034
In OpenGL, when you are creating a OpenGL texture manually, you can assign 4 types:
GL_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP and GL_CLAMP_TO_BORDER
If you want to learn more from the openGL textures differences, take a look here. Basically, it extend the last pixel in a image to the rest of the reserved memory.
In order to solve your problem, try to load the texture, modifing the parameters. I don't know if sfml allow to do it with Texture.hpp header, in the reference appear setRepeated, try to set true to see if solve the problem. Other way, loadfromfile with a size sf::IntRect(0, 0, 32, 32) in example.
This code is not tested, but teorically, using OpenGL will work:
void renderWindow::loadTexture(sf::String folder, int numTexture)
{
if (mMemoryTexture.loadFromFile("textures/" + folder + "/" + to_string(numTexture) + ".jpg"))
mTextures.push_back(mMemoryTexture);
else
cout << "Texture n°" << numTexture << " as failed to load." << endl;
// Generate OpenGL Texture manually
GLuint texture_handle;
glGenTextures(1, &texture_handle);
// Attach the texture
glBindTexture(GL_TEXTURE_2D, texture_handle);
// Upload to Graphic card
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA,
mMemoryTexture.GetWidth(), mMemoryTexture.GetHeight(),
0,
GL_RGBA, GL_UNSIGNED_BYTE, mMemoryTexture.GetPixelsPtr()
);
// Set the values
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
Maybe this helps you to solve your problem.
I endend by finding better way to do this code, thanks to members of stackoverflow. For people who got there by looking for a solution to a similar problem, I invite you to look at the comments for some usefull links and comment.

Scaling and rotating texture onto another texture by raw buffer data

I submitted this to gamedev, but they seem rather slow so I hope I could find an answer here.
I've been messing with C++ AMP and OGRE in attempt to make writing to/altering textures to my liking easier on my behalf. In this I've been trying to draw a texture onto my "dynamic" texture with strange results. It appears that a solid 3/4 of my image is cropped off and it's driving me mad as I cannot seem to find the fix.
Here's a video of the problem: http://www.youtube.com/watch?v=uFWxHtHtqAI
And here's all of the necessary code for the sake of understanding even though the kernel is really where the issue at hand rests:
DynamicTexture.h
#define ValidTexCoord(x, y, width, height) ((x) >= 0 && (x) < (width) && (y) >= 0 && (y) < (height))
void TextureKernel(array<uint32, 2> &buffer, array_view<uint32, 2> texture, uint32 x, uint32 y, Real rot, Real scale, bool alpha)
{
Real
c = cos(-rot) / scale,
s = sin(-rot) / scale;
int32
//e = int32(sqrt((texture.extent[1] * texture.extent[1]) + (texture.extent[0] * texture.extent[0])) * scale * 0.5F),
dx = texture.extent[1] / 2,
dy = texture.extent[0] / 2;
parallel_for_each(buffer.extent, [=, &buffer](index<2> idx) restrict(amp)
{
int32
tex_x = int32((Real(idx[1] - x) * c) - (Real(idx[0] - y) * s)) + dx,
tex_y = int32((Real(idx[1] - x) * s) + (Real(idx[0] - y) * c)) + dy;
if(ValidTexCoord(tex_x, tex_y, texture.extent[1], texture.extent[0]))
{
if(!alpha || (alpha && texture(tex_y, tex_x) != 0))
{
buffer(idx) = texture(tex_y, tex_x);
}
}
else
{
buffer(idx) = 0x336699FF;
}
});
}
template<typename T, int32 Rank>
void SetKernel(array<T, Rank> &arr, T val)
{
parallel_for_each(arr.extent, [&arr, val](index<Rank> idx) restrict(amp)
{
arr(idx) = val;
});
}
class DynamicTexture
{
static int32
id;
array<uint32, 2>
buffer;
public:
const int32
width,
height;
TexturePtr
textureptr;
DynamicTexture(const int32 width, const int32 height, uint32 color = 0) :
width(width),
height(height),
buffer(extent<2>(height, width))
{
SetKernel(buffer, color);
textureptr = TextureManager::getSingleton().createManual("DynamicTexture" + StringConverter::toString(++id), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TextureType::TEX_TYPE_2D, width, height, 0, PixelFormat::PF_A8R8G8B8);
}
~DynamicTexture()
{
}
void Texture(TexturePtr texture, uint32 x, uint32 y, Real rot = 0.F, Real scale = 1.F, bool alpha = false)
{
HardwarePixelBufferSharedPtr
pixelbuffer = texture->getBuffer();
TextureKernel(buffer, array_view<uint32, 2>(texture->getHeight(), texture->getWidth(), (uint32 *)pixelbuffer->lock(HardwareBuffer::HBL_READ_ONLY)), x, y, rot, scale, alpha);
pixelbuffer->unlock();
}
void CopyToBuffer()
{
HardwarePixelBufferSharedPtr
pixelbuffer = textureptr->getBuffer();
copy(buffer, stdext::make_checked_array_iterator<uint32 *>((uint32 *)pixelbuffer->lock(HardwareBuffer::HBL_DISCARD), width * height));
pixelbuffer->unlock();
}
void Reset(uint32 color)
{
SetKernel(buffer, color);
}
};
int32
DynamicTexture::id = 0;
main.cpp
void initScene()
{
dynamictexture = new DynamicTexture(window->getWidth(), window->getHeight());
TextureManager::getSingleton().load("minotaur.jpg", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TextureType::TEX_TYPE_2D, 0);
}
bool frameStarted(const FrameEvent &evt)
{
static Real
ang = 0.F;
ang += 0.05F;
if(ang > Math::TWO_PI)
{
ang = 0.F;
}
dynamictexture->Reset(0);
dynamictexture->Texture(TextureManager::getSingleton().getByName("minotaur.jpg"), dynamictexture->width / 2, dynamictexture->height / 2, ang, 4.F, true);
dynamictexture->CopyToBuffer();
return true;
}
As you can see, the dynamic texture is the size of the window (which in this case is 800x600) and the minotaur.jpg is 84x84. I'm simply placing it at half the width and height (center), rotating it by ang (radians), and scaling it to 4x.
In the kernel itself, I simply followed a 2D rotation matrix (where x and y are offset by the parameters 'x' and 'y'):
x' = x cosθ - y sinθ
y' = x sinθ + y cosθ
Also note that idx[1] represents the x value in the array and idx[0] represents the y because it's arranged in the manner that value = buffer[y + (x * height)] (or something along those lines, but just know it's in the correct format).
Thanks for any and all help!
Regards,
Tannz0rz
I found the solution thanks to this guy: https://sites.google.com/site/ofauckland/examples/rotating-pixels
const Real
HALF_PI = Math::HALF_PI;
const int32
cx = texture.extent[1] / 2,
cy = texture.extent[0] / 2;
parallel_for_each(buffer.extent, [=, &buffer](index<2> idx) restrict(amp)
{
int32
tex_x = idx[1] - x,
tex_y = idx[0] - y;
Real
dist = sqrt(Real((tex_x * tex_x) + (tex_y * tex_y))) / scale,
theta = atan2(Real(tex_y), Real(tex_x)) - angle - HALF_PI;
tex_x = int32(dist * sin(theta)) + cx;
tex_y = int32(dist * cos(theta)) + cy;
if(ValidTexCoord(tex_x, tex_y, texture.extent[1], texture.extent[0]))
{
buffer(idx) = texture(tex_y, tex_x);
}
});

Using glColorPointer with glDrawElements results in nothing being drawn

I'm working on just making uniformly colors spheres for a project and I'm running into an issue. The spheres run fine but when I try to color them with glColorPointer they stop appearing. OpenGL isn't showing any errors when I call glGetError so I'm at a loss for why this would happen.
The code to generate the vertices, colors etc:
void SphereObject::setupVertices()
{
//determine the array sizes
//vertices per row (+1 for the repeated one at the end) * three for each coordinate
//times the number of rows
int arraySize = myNumVertices * 3;
myNumIndices = (myVerticesPerRow + 1) * myRows * 2;
myVertices = new GLdouble[arraySize];
myIndices = new GLuint[myNumIndices];
myNormals = new GLdouble[arraySize];
myColors = new GLint[myNumVertices * 4];
//use spherical coordinates to calculate the vertices
double phiIncrement = 360 / myVerticesPerRow;
double thetaIncrement = 180 / (double)myRows;
int arrayIndex = 0;
int colorArrayIndex = 0;
int indicesIndex = 0;
double x, y, z = 0;
for(double theta = 0; theta <= 180; theta += thetaIncrement)
{
//loop including the repeat for the last vertex
for(double phi = 0; phi <= 360; phi += phiIncrement)
{
//make sure that the last vertex is repeated
if(360 - phi < phiIncrement)
{
x = myRadius * sin(radians(theta)) * cos(radians(0));
y = myRadius * sin(radians(theta)) * sin(radians(0));
z = myRadius * cos(radians(theta));
}
else
{
x = myRadius * sin(radians(theta)) * cos(radians(phi));
y = myRadius * sin(radians(theta)) * sin(radians(phi));
z = myRadius * cos(radians(theta));
}
myColors[colorArrayIndex] = myColor.getX();
myColors[colorArrayIndex + 1] = myColor.getY();
myColors[colorArrayIndex + 2] = myColor.getZ();
myColors[colorArrayIndex + 3] = 1;
myVertices[arrayIndex] = x;
myVertices[arrayIndex + 1] = y;
myVertices[arrayIndex + 2] = z;
if(theta <= 180 - thetaIncrement)
{
myIndices[indicesIndex] = arrayIndex / 3;
myIndices[indicesIndex + 1] = (arrayIndex / 3) + myVerticesPerRow + 1;
indicesIndex += 2;
}
arrayIndex += 3;
colorArrayIndex += 4;
}
}
}
And the code to actually render the thing
void SphereObject::render()
{
glPushMatrix();
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_INT, 0, myColors);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_DOUBLE, 0, myVertices);
glDrawElements(GL_QUAD_STRIP, myNumIndices, GL_UNSIGNED_INT, myIndices);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glPopClientAttrib();
glPopMatrix();
}
Any and all help would be appreciated. I'm really having a hard time for some reason.
When you use GL_INT (or any integer type) for color pointer, it linearly maps the largest possible integer value to 1.0f (maximum color), and 0 to 0.0f (minimum color).
Therefore unless your values of RGB and A are in the billions, they will likely appear completely black (or transparent if that's enabled). I see that you've got alpha = 1, which will essentially be zero after conversion to float.

How to texture glDrawElements

I have no Idea how I would texture something drawn by using glDrawElements?
From what I gather you need to use glTexCoordPointer? but I'm still really confused.
I'll put the whole program here so you can see what I'm doing
public class DrawWater {
public Expr2 func; // The function that is being drawn.
private String functionInput;
private boolean version_1_5; // Check is OpenGL 1.5 is available; set in init().
public boolean dataIsValid; // Set to true whenever data needs to be recomputed.
public double xMax = 5;
public double yMax = 5;
private int[] textures = new int[3]; // Storage For 3 Textures
// This is checked in the display() method before drawing.
/* Buffers to hold the points and normals for the surface. */
private FloatBuffer vBuf = BufferUtil.newFloatBuffer(201 * 201 * 3);
private FloatBuffer nBuf = BufferUtil.newFloatBuffer(201 * 201 * 3);
/* Buffers to hold the indices for drawing the surface and lines with glDrawElements*/
private IntBuffer surfaceIndexBuffer = BufferUtil.newIntBuffer(200 * 201 * 2);
private IntBuffer xLineIndexBuffer = BufferUtil.newIntBuffer(21 * 201);
private IntBuffer yLineIndexBuffer = BufferUtil.newIntBuffer(21 * 201);
/* VBO ID numbers for holding the data when OpenGL version is 1.5 or higher */
private int vertexVBO, normalVBO; // VBO IDs for surface data.
private int xLineVBO, yLineVBO, surfaceVBO; // VBO IDs for index data.
public DrawWater() {
}
public void setup(GL gl, String equ) {
this.functionInput = equ;
this.func = new Expr2(equ);
}
public void draw(GL gl) {
version_1_5 = gl.isExtensionAvailable("GL_VERSION_1_5");
if (gl.isExtensionAvailable("GL_VERSION_1_3")) {
gl.glEnable(GL.GL_MULTISAMPLE);
}
makeElementBuffers(); // Generate lists of indices for glDrawElements. This data never changes.
if (version_1_5) {
// Generate VBOs for the data, and fill the ones that are for index data with
// data from Java nio buffers. The VBOs for index data won't change again and
// so use GL.GL_STATIC_DRAW.
int[] ids = new int[5];
gl.glGenBuffers(5, ids, 0);
this.vertexVBO = ids[0];
this.normalVBO = ids[1];
this.xLineVBO = ids[2];
this.yLineVBO = ids[3];
this.surfaceVBO = ids[4];
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vertexVBO);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, 0);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, normalVBO);
gl.glNormalPointer(GL.GL_FLOAT, 0, 0);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, surfaceVBO);
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, 4 * 2 * 200 * 201, surfaceIndexBuffer, GL.GL_STATIC_DRAW);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, xLineVBO);
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, 4 * 21 * 201, xLineIndexBuffer, GL.GL_STATIC_DRAW);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, yLineVBO);
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, 4 * 21 * 201, yLineIndexBuffer, GL.GL_STATIC_DRAW);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
} else {
gl.glVertexPointer(3, GL.GL_FLOAT, 0, vBuf);
gl.glNormalPointer(GL.GL_FLOAT, 0, nBuf);
}
this.dataIsValid = false; // Force recomputation of data with new graph definition.
if (func != null) {
gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE, new float[]{0.7f, 0.7f, 1}, 0);
gl.glMaterialfv(GL.GL_BACK, GL.GL_AMBIENT_AND_DIFFUSE, new float[]{0.8f, 0.8f, 0.5f}, 0);
if (!dataIsValid) {
this.computeSurfaceData();
if (version_1_5) {
// Set up VBOs for surface points and normals. Since these change
// pretty regularly, use GL.GL_DYNAMIC_DRAW.
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vertexVBO);
gl.glBufferData(GL.GL_ARRAY_BUFFER, 4 * 3 * 201 * 201, vBuf, GL.GL_DYNAMIC_DRAW);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, normalVBO);
gl.glBufferData(GL.GL_ARRAY_BUFFER, 4 * 3 * 201 * 201, nBuf, GL.GL_DYNAMIC_DRAW);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
}
}
gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL.GL_NORMAL_ARRAY);
this.drawSurface(gl); // Just draw the surface.
gl.glPolygonOffset(1, 1);
gl.glEnable(GL.GL_POLYGON_OFFSET_FILL);
this.drawSurface(gl);
gl.glDisable(GL.GL_POLYGON_OFFSET_FILL);
gl.glDisable(GL.GL_LIGHTING);
gl.glColor3f(0, 0, 0);
gl.glDisableClientState(GL.GL_NORMAL_ARRAY);
gl.glEnable(GL.GL_LIGHTING);
}
gl.glDisableClientState(GL.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL.GL_NORMAL_ARRAY);
}
private void makeElementBuffers() {
for (int i = 0; i < 201; i += 10) { // indices for drawing lines in x-direction
for (int j = 0; j < 201; j++) {
this.xLineIndexBuffer.put(201 * i + j);
}
}
for (int i = 0; i < 201; i += 10) { // indices for drawing lines in y-direction
for (int j = 0; j < 201; j++) {
this.yLineIndexBuffer.put(201 * j + i);
}
}
for (int i = 0; i < 200; i++) { // indices for drawing surface with GL_TRIANGLE_STRIPs
for (int j = 0; j < 201; j++) {
this.surfaceIndexBuffer.put(201 * (i + 1) + j);
this.surfaceIndexBuffer.put(201 * i + j);
}
}
this.xLineIndexBuffer.rewind();
this.yLineIndexBuffer.rewind();
this.surfaceIndexBuffer.rewind();
}
private void computeSurfaceData() {
double xmin = -xMax;
double xmax = xMax;
double ymin = -yMax;
double ymax = yMax;
double xRes = 200;
double yRes = 200;
float[] surfaceData = new float[301 * 3];
float[] normalData = new float[301 * 3];
double dx = (xmax - xmin) / xRes;
double dy = (ymax - ymin) / yRes;
for (int i = 0; i <= xRes; i++) {
int v = 0;
int n = 0;
double y1 = ymin + dy * i;
for (int j = 0; j <= yRes; j++) {
double x = xmin + dx * j;
func.setVariable('x', x);
func.setVariable('y', y1);
double z1 = func.value();
float[] normal1 = computeUnitNormal(x, y1);
surfaceData[v++] = (float) x;
surfaceData[v++] = (float) y1;
surfaceData[v++] = (float) z1;
normalData[n++] = normal1[0];
normalData[n++] = normal1[1];
normalData[n++] = normal1[2];
}
vBuf.put(surfaceData, 0, 201 * 3);
nBuf.put(normalData, 0, 201 * 3);
}
vBuf.rewind();
nBuf.rewind();
dataIsValid = true;
}
/**
* Draw the surface as a series of triangle strips.
*/
private void drawSurface(GL gl) {
if (version_1_5) {
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, surfaceVBO);
for (int i = 0; i < 200; i++) {
gl.glTexCoordPointer(3, GL.GL_TRIANGLE_STRIP, 402, nBuf);
gl.glDrawElements(GL.GL_TRIANGLE_STRIP, 402, GL.GL_UNSIGNED_INT, 402 * i * 4);
}
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
} else {
for (int i = 0; i < 200; i++) {
surfaceIndexBuffer.position(402 * i);
gl.glDrawElements(GL.GL_TRIANGLE_STRIP, 402, GL.GL_UNSIGNED_INT, surfaceIndexBuffer);
}
}
}
/**
* Compute a unit normal to the graph of z = func(x,y).
* This is only an approximation, using nearby points instead
* of exact derivatives.
*/
private float[] computeUnitNormal(double x, double y) {
double epsilon = 0.00001;
func.setVariable('x', x);
func.setVariable('y', y);
double z = this.func.value();
func.setVariable('x', x + epsilon);
double z1 = func.value();
func.setVariable('x', x);
func.setVariable('y', y + epsilon);
double z2 = this.func.value();
// normal is (epsilon,0,z1-z) X (0,epsilon,z2-z)
double a = -epsilon * (z1 - z);
double b = -epsilon * (z2 - z);
double c = epsilon * epsilon;
double length = Math.sqrt(a * a + b * b + c * c);
if (Double.isNaN(length) || Double.isInfinite(length)) {
return new float[]{0, 0, 1};
} else {
return new float[]{(float) (a / length), (float) (b / length), (float) (c / length)};
}
}
private void loadGLTextures(GLAutoDrawable gldrawable) throws IOException {
TextureReader.Texture texture = null;
texture = TextureReader.readTexture("data/images/04.bmp");
GL gl = gldrawable.getGL();
//Create Nearest Filtered Texture
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL.GL_TEXTURE_2D, textures[0]);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl.glTexImage2D(GL.GL_TEXTURE_2D,
0,
3,
texture.getWidth(),
texture.getHeight(),
0,
GL.GL_RGB,
GL.GL_UNSIGNED_BYTE,
texture.getPixels());
}
}
Any help or advise would help I'm just confused ?
Ya this is the array buffer
int[] ids = new int[5];
gl.glGenBuffers(5, ids, 0);
this.vertexVBO = ids[0];
this.normalVBO = ids[1];
this.xLineVBO = ids[2];
this.yLineVBO = ids[3];
this.surfaceVBO = ids[4];
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vertexVBO);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, 0);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, normalVBO);
gl.glNormalPointer(GL.GL_FLOAT, 0, 0);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, surfaceVBO);
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, 4 * 2 * 200 * 201, surfaceIndexBuffer, GL.GL_STATIC_DRAW);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, xLineVBO);
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, 4 * 21 * 201, xLineIndexBuffer, GL.GL_STATIC_DRAW);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, yLineVBO);
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, 4 * 21 * 201, yLineIndexBuffer, GL.GL_STATIC_DRAW);
I can add the whole program if you'd like to see?
As you have created (I hope) a GL_ARRAY_BUFFER with your vertices and set it with glVertexPointer, you should create a GL_ARRAY_BUFFER with your texture coordinates and set it using glTexCoordPointer. Could you copy paste your glVertexPointer call?