Manipulating sfml Vertex Array - c++

I am doing research on the sfml Vertex Array functions.Based on this tutorial I've been introduced to a basic implementation and am wanting to add to it. Unfortunately I am relatively new at OOP and would appreciate any help adding to this.
The output generates a checkerboard like pattern using a sprite grid.
My goal is to connect the grid-floor tiles using a pathfinding algorithm(recursive bactracker) to generate a path.
the rest of this part is instantiated in the main.cpp:
//load the texture for our background vertex array
Texture textureBackground;
textureBackground.loadFromFile("graphics/background_sheet.png");
once in the game loop as:
//pass the vertex array by reference to the createBackground function
int tileSize = createBackground(background, arena);
and finally in the draw scene:
window.draw(background, &textureBackground);
#include "stdafx.h"
#include <SFML/Graphics.hpp>
#include "zArena.h"
int createBackground(VertexArray& rVA, IntRect arena)
{
// Anything we do to rVA we are actually doing to background (in the main function)
// How big is each tile/texture
const int TILE_SIZE = 50;
const int TILE_TYPES = 3;
const int VERTS_IN_QUAD = 4;
int worldWidth = arena.width / TILE_SIZE;
int worldHeight = arena.height / TILE_SIZE;
// What type of primitive are we using?
rVA.setPrimitiveType(Quads);
// Set the size of the vertex array
rVA.resize(worldWidth * worldHeight * VERTS_IN_QUAD);
// Start at the beginning of the vertex array
int currentVertex = 0;
for (int w = 0; w < worldWidth; w++)
{
for (int h = 0; h < worldHeight; h++)
{
// Position each vertex in the current quad
rVA[currentVertex + 0].position = Vector2f(w * TILE_SIZE, h * TILE_SIZE);
rVA[currentVertex + 1].position = Vector2f((w * TILE_SIZE) + TILE_SIZE, h * TILE_SIZE);
rVA[currentVertex + 2].position = Vector2f((w * TILE_SIZE) + TILE_SIZE, (h * TILE_SIZE) + TILE_SIZE);
rVA[currentVertex + 3].position = Vector2f((w * TILE_SIZE), (h * TILE_SIZE) + TILE_SIZE);
// Define the position in the Texture to draw for current quad
// Either mud, stone, grass or wall
//if (h == 0 || h == worldHeight - 1 || w == 0 || w == worldWidth - 1)
if ((h % 2 !=0)&& (w % 2 != 0))
{
// Use the wall texture
rVA[currentVertex + 0].texCoords = Vector2f(0, 0 + TILE_TYPES * TILE_SIZE);
rVA[currentVertex + 1].texCoords = Vector2f(TILE_SIZE, 0 + TILE_TYPES * TILE_SIZE);
rVA[currentVertex + 2].texCoords = Vector2f(TILE_SIZE, TILE_SIZE + TILE_TYPES * TILE_SIZE);
rVA[currentVertex + 3].texCoords = Vector2f(0, TILE_SIZE + TILE_TYPES * TILE_SIZE);
}
else
{
// Use a random floor texture
srand((int)time(0) + h * w - h);
int mOrG = (rand() % TILE_TYPES);
int verticalOffset = mOrG * TILE_SIZE;
//int verticalOffset = 0;
rVA[currentVertex + 0].texCoords = Vector2f(0, 0 + verticalOffset);
rVA[currentVertex + 1].texCoords = Vector2f(TILE_SIZE, 0 + verticalOffset);
rVA[currentVertex + 2].texCoords = Vector2f(TILE_SIZE, TILE_SIZE + verticalOffset);
rVA[currentVertex + 3].texCoords = Vector2f(0, TILE_SIZE + verticalOffset);
}
// Position ready for the next for vertices
currentVertex = currentVertex + VERTS_IN_QUAD;
}
}
return TILE_SIZE;
}

As far as i see, there you're generating your tiles on the fly. If you want to create something like a walkable space, you should generate your tile map first, and then draw it based on the content generated.
Maybe overkilling your question, there are several ways to generate random maps satisfying specific constraints.
When you have the choice done, then you can simply draw as you do, but instead of
// Use a random floor texture
srand((int)time(0) + h * w - h);
int mOrG = (rand() % TILE_TYPES);
int verticalOffset = mOrG * TILE_SIZE;
should have something like
// Select texture rect based on generated tilemap
int mOrG = tilemap[w][h]; // Or tilemap[h * worldWidth + w] if you do it as unidimensional array
int verticalOffset = mOrG * TILE_SIZE;
With this approach you must pass tilemap to your render method or, even better, create a TileMap class overriding draw() method

Related

DirectX/C++: Marching Cubes Indexing

I've implemented the Marching Cube algorithm in a DirectX environment (To test and have fun). Upon completion, I noticed that the resulting model looks heavily distorted, as if the indices were off.
I've attempted to extract the indices, but I think the vertices are ordered correctly already, using the lookup tables, examples at http://paulbourke.net/geometry/polygonise/ . The current build uses a 15^3 volume.
Marching cubes iterates over the array as normal:
for (float iX = 0; iX < CellFieldSize.x; iX++){
for (float iY = 0; iY < CellFieldSize.y; iY++){
for (float iZ = 0; iZ < CellFieldSize.z; iZ++){
MarchCubes(XMFLOAT3(iX*StepSize, iY*StepSize, iZ*StepSize), StepSize);
}
}
}
The MarchCube function is called:
void MC::MarchCubes(){
...
int Corner, Vertex, VertexTest, Edge, Triangle, FlagIndex, EdgeFlags;
float Offset;
XMFLOAT3 Color;
float CubeValue[8];
XMFLOAT3 EdgeVertex[12];
XMFLOAT3 EdgeNorm[12];
//Local copy
for (Vertex = 0; Vertex < 8; Vertex++) {
CubeValue[Vertex] = (this->*fSample)(
in_Position.x + VertexOffset[Vertex][0] * Scale,
in_Position.y + VertexOffset[Vertex][1] * Scale,
in_Position.z + VertexOffset[Vertex][2] * Scale
);
}
FlagIndex = 0;
Intersection calculations:
...
//Test vertices for intersection.
for (VertexTest = 0; VertexTest < 8; VertexTest++){
if (CubeValue[VertexTest] <= TargetValue)
FlagIndex |= 1 << VertexTest;
}
//Find which edges are intersected by the surface.
EdgeFlags = CubeEdgeFlags[FlagIndex];
if (EdgeFlags == 0){
return;
}
for (Edge = 0; Edge < 12; Edge++){
if (EdgeFlags & (1 << Edge)) {
Offset = GetOffset(CubeValue[EdgeConnection[Edge][0]], CubeValue[EdgeConnection[Edge][1]], TargetValue); // Get offset function definition. Needed!
EdgeVertex[Edge].x = in_Position.x + VertexOffset[EdgeConnection[Edge][0]][0] + Offset * EdgeDirection[Edge][0] * Scale;
EdgeVertex[Edge].y = in_Position.y + VertexOffset[EdgeConnection[Edge][0]][1] + Offset * EdgeDirection[Edge][1] * Scale;
EdgeVertex[Edge].z = in_Position.z + VertexOffset[EdgeConnection[Edge][0]][2] + Offset * EdgeDirection[Edge][2] * Scale;
GetNormal(EdgeNorm[Edge], EdgeVertex[Edge].x, EdgeVertex[Edge].y, EdgeVertex[Edge].z); //Need normal values
}
}
And the original implementation gets pushed into a holding struct for DirectX.
for (Triangle = 0; Triangle < 5; Triangle++) {
if (TriangleConnectionTable[FlagIndex][3 * Triangle] < 0) break;
for (Corner = 0; Corner < 3; Corner++) {
Vertex = TriangleConnectionTable[FlagIndex][3 * Triangle + Corner];3 * Triangle + Corner]);
GetColor(Color, EdgeVertex[Vertex], EdgeNorm[Vertex]);
Data.VertexData.push_back(XMFLOAT3(EdgeVertex[Vertex].x, EdgeVertex[Vertex].y, EdgeVertex[Vertex].z));
Data.NormalData.push_back(XMFLOAT3(EdgeNorm[Vertex].x, EdgeNorm[Vertex].y, EdgeNorm[Vertex].z));
Data.ColorData.push_back(XMFLOAT4(Color.x, Color.y, Color.z, 1.0f));
}
}
(This is the same ordering as the original GL implementation)
Turns out, I missed a parenthesis showing operator precedence.
EdgeVertex[Edge].x = in_Position.x + (VertexOffset[EdgeConnection[Edge][0]][0] + Offset * EdgeDirection[Edge][0]) * Scale;
EdgeVertex[Edge].y = in_Position.y + (VertexOffset[EdgeConnection[Edge][0]][1] + Offset * EdgeDirection[Edge][1]) * Scale;
EdgeVertex[Edge].z = in_Position.z + (VertexOffset[EdgeConnection[Edge][0]][2] + Offset * EdgeDirection[Edge][2]) * Scale;
Corrected, obtained Visine; resumed fun.

Creating a Sphere (using osg::Geometry) in OpenSceneGraph

I spent quite some time to get this working, but my Sphere just won't display.
Used the following code to make my function:
Creating a 3D sphere in Opengl using Visual C++
And the rest is simple OSG with osg::Geometry.
(Note: Not ShapeDrawable, as you can't implement custom shapes using that.)
Added the vertices, normals, texcoords into VecArrays.
For one, I suspect something misbehaving, as my saved object is half empty.
Is there a way to convert the existing description into OSG?
Reason? I want to understand how to create objects later on.
Indeed, it is linked with a later assignment, but currently I'm just prepairing beforehand.
Sidenote: Since I have to make it without indices, I left them out.
But my cylinder displays just fine without them.
Caveat: I'm not an OSG expert. But, I did do some research.
OSG requires all of the faces to be defined in counter-clockwise order, so that backface culling can reject faces that are "facing away". The code you're using to generate the sphere does not generate all the faces in counter-clockwise order.
You can approach this a couple ways:
Adjust how the code generates the faces, by inserting the faces CCW order.
Double up your model and insert each face twice, once with the vertices on each face in their current order and once with the vertices in reverse order.
Option 1 above will limit your total polygon count to what's needed. Option 2 will give you a sphere that's visible from outside the sphere as well as within.
To implement Option 2, you merely need to modify this loop from the code you linked to:
indices.resize(rings * sectors * 4);
std::vector<GLushort>::iterator i = indices.begin();
for(r = 0; r < rings-1; r++)
for(s = 0; s < sectors-1; s++) {
*i++ = r * sectors + s;
*i++ = r * sectors + (s+1);
*i++ = (r+1) * sectors + (s+1);
*i++ = (r+1) * sectors + s;
}
Double up the set of quads like so:
indices.resize(rings * sectors * 8);
std::vector<GLushort>::iterator i = indices.begin();
for(r = 0; r < rings-1; r++)
for(s = 0; s < sectors-1; s++) {
*i++ = r * sectors + s;
*i++ = r * sectors + (s+1);
*i++ = (r+1) * sectors + (s+1);
*i++ = (r+1) * sectors + s;
*i++ = (r+1) * sectors + s;
*i++ = (r+1) * sectors + (s+1);
*i++ = r * sectors + (s+1);
*i++ = r * sectors + s;
}
That really is the "bigger hammer" solution, though.
Personally, I'm having a hard time figuring out why the original loop isn't sufficient; intuiting my way through the geometry, it feels like it's already generating CCW faces, because each successive ring is above the previous, and each successive sector is CCW around the surface of the sphere from the previous. So, the original order itself should be CCW with respect to the face nearest the viewer.
EDIT Using the OpenGL code you linked before and the OSG tutorial you linked today, I put together what I think is a correct program to generate the osg::Geometry / osg::Geode for the sphere. I have no way to test the following code, but desk-checking it, it looks correct or at least largely correct.
#include <vector>
class SolidSphere
{
protected:
osg::Geode sphereGeode;
osg::Geometry sphereGeometry;
osg::Vec3Array sphereVertices;
osg::Vec3Array sphereNormals;
osg::Vec2Array sphereTexCoords;
std::vector<osg::DrawElementsUInt> spherePrimitiveSets;
public:
SolidSphere(float radius, unsigned int rings, unsigned int sectors)
{
float const R = 1./(float)(rings-1);
float const S = 1./(float)(sectors-1);
int r, s;
sphereGeode.addDrawable( &sphereGeometry );
// Establish texture coordinates, vertex list, and normals
for(r = 0; r < rings; r++)
for(s = 0; s < sectors; s++)
{
float const y = sin( -M_PI_2 + M_PI * r * R );
float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );
sphereTexCoords.push_back( osg::Vec2(s*R, r*R) );
sphereVertices.push_back ( osg::Vec3(x * radius,
y * radius,
z * radius) );
sphereNormals.push_back ( osg::Vec3(x, y, z) );
}
sphereGeometry.setVertexArray ( &spehreVertices );
sphereGeometry.setTexCoordArray( &sphereTexCoords );
// Generate quads for each face.
for(r = 0; r < rings-1; r++)
for(s = 0; s < sectors-1; s++)
{
spherePrimitiveSets.push_back(
DrawElementUint( osg::PrimitiveSet::QUADS, 0 )
);
osg::DrawElementsUInt& face = spherePrimitiveSets.back();
// Corners of quads should be in CCW order.
face.push_back( (r + 0) * sectors + (s + 0) );
face.push_back( (r + 0) * sectors + (s + 1) );
face.push_back( (r + 1) * sectors + (s + 1) );
face.push_back( (r + 1) * sectors + (s + 0) );
sphereGeometry.addPrimitveSet( &face );
}
}
osg::Geode *getGeode() const { return &sphereGeode; }
osg::Geometry *getGeometry() const { return &sphereGeometry; }
osg::Vec3Array *getVertices() const { return &sphereVertices; }
osg::Vec3Array *getNormals() const { return &sphereNormals; }
osg::Vec2Array *getTexCoords() const { return &sphereTexCoords; }
};
You can use the getXXX methods to get the various pieces. I didn't see how to hook the surface normals to anything, but I do store them in a Vec2Array. If you have a use for them, they're computed and stored and waiting to be hooked to something.
That code calls glutSolidSphere() to draw a sphere, but it doesn't make sense to call it if your application is not using GLUT to display a window with 3D context.
There is another way to draw a sphere easily, which is by invoking gluSphere() (you probably have GLU installed):
void gluSphere(GLUquadric* quad,
GLdouble radius,
GLint slices,
GLint stacks);
Parameters
quad - Specifies the quadrics object (created with gluNewQuadric).
radius - Specifies the radius of the sphere.
slices - Specifies the number of subdivisions around the z axis (similar
to lines of longitude).
stacks - Specifies the number of subdivisions along the z axis (similar
to lines of latitude).
Usage:
// If you also need to include glew.h, do it before glu.h
#include <glu.h>
GLUquadric* _quadratic = gluNewQuadric();
if (_quadratic == NULL)
{
std::cerr << "!!! Failed gluNewQuadric" << std::endl;
return;
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -5.0);
glColor3ub(255, 97, 3);
gluSphere(_quadratic, 1.4f, 64, 64);
glFlush();
gluDeleteQuadric(_quadratic);
It's probably wiser to move the gluNewQuadric() call to the constructor of your class since it needs to be allocated only once, and move the call to gluDeleteQuadric() to the destructor of the class.
#JoeZ's answer is excellent, but the OSG code has some errors/bad practices. Here's the updated code. It's been tested and it shows a very nice sphere.
osg::ref_ptr<osg::Geode> buildSphere( const double radius,
const unsigned int rings,
const unsigned int sectors )
{
osg::ref_ptr<osg::Geode> sphereGeode = new osg::Geode;
osg::ref_ptr<osg::Geometry> sphereGeometry = new osg::Geometry;
osg::ref_ptr<osg::Vec3Array> sphereVertices = new osg::Vec3Array;
osg::ref_ptr<osg::Vec3Array> sphereNormals = new osg::Vec3Array;
osg::ref_ptr<osg::Vec2Array> sphereTexCoords = new osg::Vec2Array;
float const R = 1. / static_cast<float>( rings - 1 );
float const S = 1. / static_cast<float>( sectors - 1 );
sphereGeode->addDrawable( sphereGeometry );
// Establish texture coordinates, vertex list, and normals
for( unsigned int r( 0 ); r < rings; ++r ) {
for( unsigned int s( 0) ; s < sectors; ++s ) {
float const y = sin( -M_PI_2 + M_PI * r * R );
float const x = cos( 2 * M_PI * s * S) * sin( M_PI * r * R );
float const z = sin( 2 * M_PI * s * S) * sin( M_PI * r * R );
sphereTexCoords->push_back( osg::Vec2( s * R, r * R ) );
sphereVertices->push_back ( osg::Vec3( x * radius,
y * radius,
z * radius) )
;
sphereNormals->push_back ( osg::Vec3( x, y, z ) );
}
}
sphereGeometry->setVertexArray ( sphereVertices );
sphereGeometry->setTexCoordArray( 0, sphereTexCoords );
// Generate quads for each face.
for( unsigned int r( 0 ); r < rings - 1; ++r ) {
for( unsigned int s( 0 ); s < sectors - 1; ++s ) {
osg::ref_ptr<osg::DrawElementsUInt> face =
new osg::DrawElementsUInt( osg::PrimitiveSet::QUADS,
4 )
;
// Corners of quads should be in CCW order.
face->push_back( ( r + 0 ) * sectors + ( s + 0 ) );
face->push_back( ( r + 0 ) * sectors + ( s + 1 ) );
face->push_back( ( r + 1 ) * sectors + ( s + 1 ) );
face->push_back( ( r + 1 ) * sectors + ( s + 0 ) );
sphereGeometry->addPrimitiveSet( face );
}
}
return sphereGeode;
}
Changes:
The OSG elements used in the code now are smart pointers1. Moreover, classes like Geode and Geometry have their destructors protected, so the only way to instantiate them are via dynamic allocation.
Removed spherePrimitiveSets as it isn't needed in the current version of the code.
I put the code in a free function, as I don't need a Sphere class in my code. I omitted the getters and the protected attributes. They aren't needed: if you need to access, say, the geometry, you can get it via: sphereGeode->getDrawable(...). The same goes for the rest of the attributes.
[1] See Rule of thumb #1 here. It's a bit old but the advice maintains.

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.

A method for indexing triangles from a loaded heightmap?

I am currently making a method to load in a noisy heightmap, but lack the triangles to do so. I want to make an algorithm that will take an image, its width and height and construct a terrain node out of it.
Here's what I have so far, in somewhat pseudo
Vertex* vertices = new Vertices[image.width * image.height];
Index* indices; // How do I judge how many indices I will have?
float scaleX = 1 / image.width;
float scaleY = 1 / image.height;
float currentYScale = 0;
for(int y = 0; y < image.height; ++y) {
float currentXScale = 0;
for (int x = 0; x < image.width; ++x) {
Vertex* v = vertices[x * y];
v.x = currentXScale;
v.y = currentYScale;
v.z = image[x,y];
currentXScale += scaleX;
}
currentYScale += scaleY;
}
This works well enough to my needs, my only problem is this: How would I calculate the # of indices and their positions for drawing the triangles? I have somewhat familiarity with indices, but not how to programmatically calculate them, I can only do that statically.
As far as your code above goes, using vertices[x * y] isn't right - if you use that, then e.g. vert(2,3) == vert(3,2). What you want is something like vertices[y * image.width + x], but you can do it more efficiently by incrementing a counter (see below).
Here's the equivalent code I use. It's in C# unfortunately, but hopefully it should illustrate the point:
/// <summary>
/// Constructs the vertex and index buffers for the terrain (for use when rendering the terrain).
/// </summary>
private void ConstructBuffers()
{
int heightmapHeight = Heightmap.GetLength(0);
int heightmapWidth = Heightmap.GetLength(1);
int gridHeight = heightmapHeight - 1;
int gridWidth = heightmapWidth - 1;
// Construct the individual vertices for the terrain.
var vertices = new VertexPositionTexture[heightmapHeight * heightmapWidth];
int vertIndex = 0;
for(int y = 0; y < heightmapHeight; ++y)
{
for(int x = 0; x < heightmapWidth; ++x)
{
var position = new Vector3(x, y, Heightmap[y,x]);
var texCoords = new Vector2(x * 2f / heightmapWidth, y * 2f / heightmapHeight);
vertices[vertIndex++] = new VertexPositionTexture(position, texCoords);
}
}
// Create the vertex buffer and fill it with the constructed vertices.
this.VertexBuffer = new VertexBuffer(Renderer.GraphicsDevice, typeof(VertexPositionTexture), vertices.Length, BufferUsage.WriteOnly);
this.VertexBuffer.SetData(vertices);
// Construct the index array.
var indices = new short[gridHeight * gridWidth * 6]; // 2 triangles per grid square x 3 vertices per triangle
int indicesIndex = 0;
for(int y = 0; y < gridHeight; ++y)
{
for(int x = 0; x < gridWidth; ++x)
{
int start = y * heightmapWidth + x;
indices[indicesIndex++] = (short)start;
indices[indicesIndex++] = (short)(start + 1);
indices[indicesIndex++] = (short)(start + heightmapWidth);
indices[indicesIndex++] = (short)(start + 1);
indices[indicesIndex++] = (short)(start + 1 + heightmapWidth);
indices[indicesIndex++] = (short)(start + heightmapWidth);
}
}
// Create the index buffer.
this.IndexBuffer = new IndexBuffer(Renderer.GraphicsDevice, typeof(short), indices.Length, BufferUsage.WriteOnly);
this.IndexBuffer.SetData(indices);
}
I guess the key point is that given a heightmap of size heightmapHeight * heightmapWidth, you need (heightmapHeight - 1) * (heightmapWidth - 1) * 6 indices, since you're drawing:
2 triangles per grid square
3 vertices per triangle
(heightmapHeight - 1) * (heightmapWidth - 1) grid squares in your terrain.

Run-Time Check Failure #2 - Stack around the variable 'indices' was corrupted

well I think I know what the problem is. I am just having a hard time debugging it. I am working with the directx api and I am trying to generate a plane along the x and z axis according to a book I have. The problem is when I am creating my indices. I think I am setting values out of the bounds of the indices array. I am just having a hard time figuring out what I did wrong. I am unfamiliar with the this method of generating a plane. so its a little difficult for me. below is my code. Take emphasis on the indices loop.
[edit]
Ive been reviewing it. This is how the indices works
int curVertex = x + (z * NUM_VERTSX);
This always gets the beginning vertices. so say we have 17 vertices on the x axis and 17 vertices on the z axis and we are on the first loop of the x and z axis
curVertx = 0 + (0 * 17)
curVertx = 0 + 0 = 0
say we are on the first loop of the z axis and second loop of the x axis
curVertx = 1 + (0 * 17)
curVertx = 1+ 0 = 1
indices[curIndex] = curVertex;
indices[curIndex + 1] = curVertex + NUM_VERTSX;
indices[curIndex + 2] = curVertex + 1;
indices[curIndex + 3] = curVertex + 1;
indices[curIndex + 4] = curVertex + NUM_VERTSX;
indices[curIndex + 5] = curVertex + NUM_VERTSX + 1;
if we are on the first
loop indices[curIndex] = curVertex;
this equals the first vertex = 0.
indices[curIndex + 1] = curVertex + NUM_VERTSX;
this equals the second row vertices (its always the vertices below the starting vertices
x x x x
[x] x x x
#include "MyGame.h"
//#include "CubeVector.h"
/* This code sets a projection and shows a turning cube. What has been added is the project, rotation and
a rasterizer to change the rasterization of the cube. The issue that was going on was something with the effect file
which was causing the vertices not to be rendered correctly.*/
typedef struct
{
ID3D10Effect* pEffect;
ID3D10EffectTechnique* pTechnique;
//vertex information
ID3D10Buffer* pVertexBuffer;
ID3D10Buffer* pIndicesBuffer;
ID3D10InputLayout* pVertexLayout;
UINT numVertices;
UINT numIndices;
}ModelObject;
ModelObject modelObject;
// World Matrix
D3DXMATRIX WorldMatrix;
// View Matrix
D3DXMATRIX ViewMatrix;
// Projection Matrix
D3DXMATRIX ProjectionMatrix;
ID3D10EffectMatrixVariable* pProjectionMatrixVariable = NULL;
//grid information
#define NUM_COLS 16
#define NUM_ROWS 16
#define CELL_WIDTH 32
#define CELL_HEIGHT 32
#define NUM_VERTSX (NUM_COLS + 1)
#define NUM_VERTSY (NUM_ROWS + 1)
bool MyGame::InitDirect3D()
{
if(!DX3dApp::InitDirect3D())
{
return false;
}
D3D10_RASTERIZER_DESC rastDesc;
rastDesc.FillMode = D3D10_FILL_WIREFRAME;
rastDesc.CullMode = D3D10_CULL_FRONT;
rastDesc.FrontCounterClockwise = true;
rastDesc.DepthBias = false;
rastDesc.DepthBiasClamp = 0;
rastDesc.SlopeScaledDepthBias = 0;
rastDesc.DepthClipEnable = false;
rastDesc.ScissorEnable = false;
rastDesc.MultisampleEnable = false;
rastDesc.AntialiasedLineEnable = false;
ID3D10RasterizerState *g_pRasterizerState;
mpD3DDevice->CreateRasterizerState(&rastDesc, &g_pRasterizerState);
mpD3DDevice->RSSetState(g_pRasterizerState);
// Set up the World Matrix
D3DXMatrixIdentity(&WorldMatrix);
D3DXMatrixLookAtLH(&ViewMatrix, new D3DXVECTOR3(0.0f, 10.0f, -20.0f), new D3DXVECTOR3(0.0f, 0.0f, 0.0f), new D3DXVECTOR3(0.0f, 1.0f, 0.0f));
// Set up the projection matrix
D3DXMatrixPerspectiveFovLH(&ProjectionMatrix, (float)D3DX_PI * 0.5f, (float)mWidth/(float)mHeight, 0.1f, 100.0f);
if(!CreateObject())
{
return false;
}
return true;
}
//These are actions that take place after the clearing of the buffer and before the present
void MyGame::GameDraw()
{
static float rotationAngle = 0.0f;
// create the rotation matrix using the rotation angle
D3DXMatrixRotationY(&WorldMatrix, rotationAngle);
rotationAngle += (float)D3DX_PI * 0.0f;
// Set the input layout
mpD3DDevice->IASetInputLayout(modelObject.pVertexLayout);
// Set vertex buffer
UINT stride = sizeof(VertexPos);
UINT offset = 0;
mpD3DDevice->IASetVertexBuffers(0, 1, &modelObject.pVertexBuffer, &stride, &offset);
mpD3DDevice->IASetIndexBuffer(modelObject.pIndicesBuffer, DXGI_FORMAT_R32_UINT, 0);
// Set primitive topology
mpD3DDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Combine and send the final matrix to the shader
D3DXMATRIX finalMatrix = (WorldMatrix * ViewMatrix * ProjectionMatrix);
pProjectionMatrixVariable->SetMatrix((float*)&finalMatrix);
// make sure modelObject is valid
// Render a model object
D3D10_TECHNIQUE_DESC techniqueDescription;
modelObject.pTechnique->GetDesc(&techniqueDescription);
// Loop through the technique passes
for(UINT p=0; p < techniqueDescription.Passes; ++p)
{
modelObject.pTechnique->GetPassByIndex(p)->Apply(0);
// draw the cube using all 36 vertices and 12 triangles
mpD3DDevice->DrawIndexed(modelObject.numIndices,0,0);
}
}
//Render actually incapsulates Gamedraw, so you can call data before you actually clear the buffer or after you
//present data
void MyGame::Render()
{
DX3dApp::Render();
}
bool MyGame::CreateObject()
{
VertexPos vertices[NUM_VERTSX * NUM_VERTSY];
for(int z=0; z < NUM_VERTSY; ++z)
{
for(int x = 0; x < NUM_VERTSX; ++x)
{
vertices[x + z * NUM_VERTSX].pos.x = (float)x * CELL_WIDTH;
vertices[x + z * NUM_VERTSX].pos.z = (float)z * CELL_HEIGHT;
vertices[x + z * NUM_VERTSX].pos.y = 0.0f;
vertices[x + z * NUM_VERTSX].color = D3DXVECTOR4(1.0, 0.0f, 0.0f, 0.0f);
}
}
DWORD indices[NUM_VERTSX * NUM_VERTSY];
int curIndex = 0;
for(int z=0; z < NUM_ROWS; ++z)
{
for(int x = 0; x < NUM_COLS; ++x)
{
int curVertex = x + (z * NUM_VERTSX);
indices[curIndex] = curVertex;
indices[curIndex + 1] = curVertex + NUM_VERTSX;
indices[curIndex + 2] = curVertex + 1;
indices[curIndex + 3] = curVertex + 1;
indices[curIndex + 4] = curVertex + NUM_VERTSX;
indices[curIndex + 5] = curVertex + NUM_VERTSX + 1;
curIndex += 6;
}
}
//Create Layout
D3D10_INPUT_ELEMENT_DESC layout[] = {
{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT, 0 , 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT, 0 , 12, D3D10_INPUT_PER_VERTEX_DATA, 0}
};
UINT numElements = (sizeof(layout)/sizeof(layout[0]));
modelObject.numVertices = sizeof(vertices)/sizeof(VertexPos);
//Create buffer desc
D3D10_BUFFER_DESC bufferDesc;
bufferDesc.Usage = D3D10_USAGE_DEFAULT;
bufferDesc.ByteWidth = sizeof(VertexPos) * modelObject.numVertices;
bufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA initData;
initData.pSysMem = vertices;
//Create the buffer
HRESULT hr = mpD3DDevice->CreateBuffer(&bufferDesc, &initData, &modelObject.pVertexBuffer);
if(FAILED(hr))
return false;
modelObject.numIndices = sizeof(indices)/sizeof(DWORD);
bufferDesc.ByteWidth = sizeof(DWORD) * modelObject.numIndices;
bufferDesc.BindFlags = D3D10_BIND_INDEX_BUFFER;
initData.pSysMem = indices;
hr = mpD3DDevice->CreateBuffer(&bufferDesc, &initData, &modelObject.pIndicesBuffer);
if(FAILED(hr))
return false;
/////////////////////////////////////////////////////////////////////////////
//Set up fx files
LPCWSTR effectFilename = L"effect.fx";
modelObject.pEffect = NULL;
hr = D3DX10CreateEffectFromFile(effectFilename,
NULL,
NULL,
"fx_4_0",
D3D10_SHADER_ENABLE_STRICTNESS,
0,
mpD3DDevice,
NULL,
NULL,
&modelObject.pEffect,
NULL,
NULL);
if(FAILED(hr))
return false;
pProjectionMatrixVariable = modelObject.pEffect->GetVariableByName("Projection")->AsMatrix();
//Dont sweat the technique. Get it!
LPCSTR effectTechniqueName = "Render";
modelObject.pTechnique = modelObject.pEffect->GetTechniqueByName(effectTechniqueName);
if(modelObject.pTechnique == NULL)
return false;
//Create Vertex layout
D3D10_PASS_DESC passDesc;
modelObject.pTechnique->GetPassByIndex(0)->GetDesc(&passDesc);
hr = mpD3DDevice->CreateInputLayout(layout, numElements,
passDesc.pIAInputSignature,
passDesc.IAInputSignatureSize,
&modelObject.pVertexLayout);
if(FAILED(hr))
return false;
return true;
}
Your indices array contains 6 entries per 'cell' (since you're drawing two triangles for each), therefore it should be declared as
DWORD indices[NUM_ROWS * NUM_COLS * 6]
The error you get tells you, that you write outside the boundaries of indices, this is usually either a hint towards a wrong declaration (or a wrong index calculation).
Now let us take the code snippet in question (probable root cause)
Code
DWORD indices[NUM_VERTSX * NUM_VERTSY];
int curIndex = 0;
for(int z=0; z < NUM_ROWS; ++z)
{
for(int x = 0; x < NUM_COLS; ++x)
{
int curVertex = x + (z * NUM_VERTSX);
indices[curIndex] = curVertex;
indices[curIndex + 1] = curVertex + NUM_VERTSX;
indices[curIndex + 2] = curVertex + 1;
indices[curIndex + 3] = curVertex + 1;
indices[curIndex + 4] = curVertex + NUM_VERTSX;
indices[curIndex + 5] = curVertex + NUM_VERTSX + 1;
curIndex += 6;
}
}
Analysis
Here indices have max number of 'cells' = NUM_VERTX * NUM_VERTSY = (16 + 1) * (16+1) = 289. So there are 0...288 'cells'. During the boundary condition - there value of z = 15, x = 15. So curIndex would be 15 * 15 * 6 = 1350. This far exceeds allocated cells.
Suggestion
Since three values determine the size of the target array, all three must be part of the allocation of the array. so if you use DWORD indices[NUM_VERTSX * NUM_VERTSY * UNIT_BLOCK], where UNIT_BLOCK = 6, it should work fine.
Also instead of embedding magic number inside the code, you can use a const variable - it would help a great deal later (if you want to change the value of the index).
HTH