Related
I have been experimenting with 3d projection for a while,
but I've always used vertexes in -1 1 range I want to use units that are 1pixel big, so I use glm::ortho(-width / 2, width / 2, -height/2, height, 0.1f, 10.0f);
but that doesn't work
heres the code with glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, 0.1f,1.0f):
#include "Engine.h"
#include "vendor/stb/stb_image.h"
float width = 1200;
float height = 750;
// edits in imgui files have farouk comment before them
int main(void)
{
initGLFW();
GLFWimage icon;
icon.pixels = stbi_load("data/Images/Icon.png", &icon.width, &icon.height, nullptr, 4);
GLFWimage image;
image.pixels = stbi_load("data/Images/Cursor.png", &image.width, &image.height, nullptr, 4);
GLFWcursor * cursor = glfwCreateCursor(&image, image.width / 2, image.height / 2);
glfwWindowHint(GLFW_SAMPLES, 6);
glEnable(GL_MULTISAMPLE);
Window window("OGL", width, height, MVP());
Renderer renderer;
renderer.GenerateFonts({"data/fonts/arial.ttf", "data/fonts/Pixelboy.ttf"}, {"arial", "roboto"}, {64, 64});
// set perspective projection & set xyz ranges from -1, 1 to respective ranges
window.mvp.projection = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, 0.1f, 10.0f);
window.createWindow("data/Images/Cursor.png", "data/Images/Icon.png");
glfwSetWindowIcon(window.window, 1, &icon);
glfwSetCursor(window.window, cursor);
stbi_image_free(image.pixels);
stbi_image_free(icon.pixels);
glfwMakeContextCurrent(window.window);
initGLEW(true);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
renderer.loadFonts({"arial", "roboto"});
initImGUI(window.window, "data/fonts/arial.ttf");
Shader shader("data/shaders/base.shader");
// TODO: Add Multiple Window Support (Window Manager)
// Addd .txt file for text with Characters map insteadt loaf Fonts
// texture in 3d space & 3d textures
// map -1, 1 to -width/2 , width/2
std::vector <Obj> cubes = {
{
{
{ {-0.5, -0.5, -1.1}, {1,1,1,1} },
{ {-0.5, 0.5, -1.1}, {1,1,1,1} },
{ {0.5, 0.5, -1.1}, {1,1,1,1} },
{ {0.5, -0.5, -1.1}, {1,1,1,1} },
{ {-0.5, -0.5, -2.1}, {0,1,1,1} },
{ {-0.5, 0.5, -2.1}, {0,1,1,1} },
{ {0.5, 0.5, -2.1}, {0,1,1,1} },
{ {0.5, -0.5, -2.1}, {0,1,1,1} },
},
{
0,1,2, 2,3,0, 4,5,6, 6,7,4, 0,4,5, 1,5,0
},
true
}
};
float tx = 0;
float ty = 0;
float tz = 0;
while (!glfwWindowShouldClose(window.window) )
{
glfwMakeContextCurrent(window.window);
renderer.Clear({0.0, 0.0, 0.0, 1});
// feed inputs to dear imgui, start new frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
renderer.Draw(shader, window.mvp, cubes);
window.mvp.view = glm::translate(glm::mat4(1), glm::vec3(0, 0, -1.6)) * glm::rotate(glm::mat4(1), glm::radians(tx), glm::vec3(1,0,0)) * glm::rotate(glm::mat4(1), glm::radians(ty), glm::vec3(0,1,0)) * glm::rotate(glm::mat4(1), glm::radians(tz), glm::vec3(0,0,1));
window.mvp.view = glm::translate(window.mvp.view, glm::vec3(0, 0, 1.6));
renderer.Text(shader, MVP(glm::mat4(1.0), glm::mat4(1.0),glm::ortho(0.0, (double)width, 0.0, (double)height)), {(TextObj){"roboto", "FPS:" + std::to_string((int)ImGui::GetIO().Framerate), 0.01424501424f * height, 0.01424501424f * height, 0, 0.02849002849f * height, 0, {1,1,1,1}}});
// render your GUI
ImGui::Begin("Demo window");
ImGui::Button("Hello!");
ImGui::SliderFloat("x", &tx, 0, 360, "%.0f", 1.0f);
ImGui::SliderFloat("y", &ty, 0, 360, "%.0f", 1.0f);
ImGui::SliderFloat("z", &tz, 0, 360, "%.0f", 1.0f);
ImGui::End();
// Render dear imgui into screen
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
int display_w, display_h;
glfwGetFramebufferSize(window.window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
glfwSwapBuffers(window.window);
glfwSwapInterval(1);
glfwPollEvents();
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
return 0;
}
and the output:
and heres the code with glm::ortho(-width / 2, width / 2, -height/2, height, 0.1f, 10.0f):
#include "Engine.h"
#include "vendor/stb/stb_image.h"
float width = 1200;
float height = 750;
// edits in imgui files have farouk comment before them
int main(void)
{
initGLFW();
GLFWimage icon;
icon.pixels = stbi_load("data/Images/Icon.png", &icon.width, &icon.height, nullptr, 4);
GLFWimage image;
image.pixels = stbi_load("data/Images/Cursor.png", &image.width, &image.height, nullptr, 4);
GLFWcursor * cursor = glfwCreateCursor(&image, image.width / 2, image.height / 2);
glfwWindowHint(GLFW_SAMPLES, 6);
glEnable(GL_MULTISAMPLE);
Window window("OGL", width, height, MVP());
Renderer renderer;
renderer.GenerateFonts({"data/fonts/arial.ttf", "data/fonts/Pixelboy.ttf"}, {"arial", "roboto"}, {64, 64});
// set perspective projection & set xyz ranges from -1, 1 to respective ranges
window.mvp.projection = glm::ortho(-width / 2, width / 2, -height/2, height, 0.1f, 10.0f);
window.createWindow("data/Images/Cursor.png", "data/Images/Icon.png");
glfwSetWindowIcon(window.window, 1, &icon);
glfwSetCursor(window.window, cursor);
stbi_image_free(image.pixels);
stbi_image_free(icon.pixels);
glfwMakeContextCurrent(window.window);
initGLEW(true);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
renderer.loadFonts({"arial", "roboto"});
initImGUI(window.window, "data/fonts/arial.ttf");
Shader shader("data/shaders/base.shader");
// TODO: Add Multiple Window Support (Window Manager)
// Addd .txt file for text with Characters map insteadt loaf Fonts
// texture in 3d space & 3d textures
// map -1, 1 to -width/2 , width/2
std::vector <Obj> cubes = {
{
{
{ {-300, -300, -1.1}, {1,1,1,1} },
{ {-300, 300, -1.1}, {1,1,1,1} },
{ {300, 300, -1.1}, {1,1,1,1} },
{ {300, -300, -1.1}, {1,1,1,1} },
{ {-300, -300, -2.1}, {0,1,1,1} },
{ {-300, 300, -2.1}, {0,1,1,1} },
{ {300, 300, -2.1}, {0,1,1,1} },
{ {300, -300, -2.1}, {0,1,1,1} },
},
{
0,1,2, 2,3,0, 4,5,6, 6,7,4, 0,4,5, 1,5,0
},
true
}
};
float tx = 0;
float ty = 0;
float tz = 0;
while (!glfwWindowShouldClose(window.window) )
{
glfwMakeContextCurrent(window.window);
renderer.Clear({0.0, 0.0, 0.0, 1});
// feed inputs to dear imgui, start new frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
renderer.Draw(shader, window.mvp, cubes);
window.mvp.view = glm::translate(glm::mat4(1), glm::vec3(0, 0, -1.6)) * glm::rotate(glm::mat4(1), glm::radians(tx), glm::vec3(1,0,0)) * glm::rotate(glm::mat4(1), glm::radians(ty), glm::vec3(0,1,0)) * glm::rotate(glm::mat4(1), glm::radians(tz), glm::vec3(0,0,1));
window.mvp.view = glm::translate(window.mvp.view, glm::vec3(0, 0, 1.6));
renderer.Text(shader, MVP(glm::mat4(1.0), glm::mat4(1.0),glm::ortho(0.0, (double)width, 0.0, (double)height)), {(TextObj){"roboto", "FPS:" + std::to_string((int)ImGui::GetIO().Framerate), 0.01424501424f * height, 0.01424501424f * height, 0, 0.02849002849f * height, 0, {1,1,1,1}}});
// render your GUI
ImGui::Begin("Demo window");
ImGui::Button("Hello!");
ImGui::SliderFloat("x", &tx, 0, 360, "%.0f", 1.0f);
ImGui::SliderFloat("y", &ty, 0, 360, "%.0f", 1.0f);
ImGui::SliderFloat("z", &tz, 0, 360, "%.0f", 1.0f);
ImGui::End();
// Render dear imgui into screen
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
int display_w, display_h;
glfwGetFramebufferSize(window.window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
glfwSwapBuffers(window.window);
glfwSwapInterval(1);
glfwPollEvents();
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
return 0;
}
and the output:
notice that i chane the vertexes from 0.5 to 300 so thats not a problem
explanation of obj struct
{
// vertexes -> vbo
{ {-0.5, -0.5, -1.1}, {1,1,1,1} }, glm::vec3 pos, glm::vec4 col
{ {-0.5, 0.5, -1.1}, {1,1,1,1} },
{ {0.5, 0.5, -1.1}, {1,1,1,1} },
{ {0.5, -0.5, -1.1}, {1,1,1,1} },
{ {-0.5, -0.5, -2.1}, {0,1,1,1} },
{ {-0.5, 0.5, -2.1}, {0,1,1,1} },
{ {0.5, 0.5, -2.1}, {0,1,1,1} },
{ {0.5, -0.5, -2.1}, {0,1,1,1} },
},
{
// indexex -> ibo
0,1,2, 2,3,0, 4,5,6, 6,7,4, 0,4,5, 1,5,0
},
true // fill -> GL_TRIANGLES or GL_LINES
}
Thanks to #derhass for the clarification the cuboid that I was drawing was too thin and my Z far value was too short I've adjusted it to 1000.0f and now everything works great
here is his comment:
"The problem is that the cube becomes a line". There are no cubes in your vertex data, there is a cuboid sized 600x600x1, so if you look at it at certain angles, it will look very thin of course. And furthermore, you will run into clipping issues as your z range is only 10 units.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
In opengl, I was attempting to write a program that would be able to draw multiple rectangles across the screen using triangles. Instead of writing down all of the vertices by hand, I wrote a nested for loop to generate the vertices. However, instead of drawing all the triangles, this program only outputs the last two triangles as a rectangle(see the pictures below). I'm sure that this way of generating triangles is hilariously bad and inefficient but that's not my main gripe with the output of this code.
Below is the nested for loop that adds the vertices to the array(be warned this code is absolutely disgusting)
float initTri1[] = { -1.5f, 0.5f, 0.0f, -1.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f };
float initTri2[] = { -1.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.5f, 0.0f };
float vertices[18*4];
float increment =0.0f;
// draws an amount of rectangles equal to the number after 18 in vertices
for (int j = 0; j < sizeof(vertices)/sizeof(vertices[0])/18; j++)
{
increment += 0.5f;
// draws triangle with hypotenuse on right side
for (int i = 0; i < 9; i++)
{
// shifts the value of the initial triangles x verticies by 0.5
if ((i + 1) % 3 != 1)
{
vertices[i+j*9] = initTri1[i];
}
// keeps the y and z values the same as the initial triangle.
else
{
vertices[i+j*9] = initTri1[i] + increment;
}
}
// sometimes draws the triangle with the hypotenuse on the left side
for (int i = 9; i < 18; i++)
{
// shifts the value of the initial triangles x verticies by 0.5
if ((i + 1) % 3 != 1)
{
vertices[i+j*9] = initTri2[i - 9];
}
// keeps the y and z values the same as the initial triangle.
else
{
vertices[i+j*9] = initTri2[i - 9] + increment;
}
}
}
Below are images of the outcome of generating: 2 triangles, 4 triangles, and 8 triangles respectively.
I didn't feel able to follow the index computations of OP. It was easier to try it out. The result looks wrong:
vertices[0]: -1, 0.5, 0
vertices[3]: -1, 0, 0
vertices[6]: -0.5, 0, 0
vertices[9]: -0.5, 0.5, 0
vertices[12]: -0.5, 0, 0
vertices[15]: 0, 0, 0
vertices[18]: 0, 0.5, 0
vertices[21]: 0, 0, 0
vertices[24]: 0.5, 0, 0
vertices[27]: 0.5, 0.5, 0
vertices[30]: 0.5, 0, 0
vertices[33]: 1, 0, 0
vertices[36]: 0.5, 0.5, 0
vertices[39]: 1, 0, 0
vertices[42]: 1, 0.5, 0
vertices[45]: 0, 8.40779e-45, 0
vertices[48]: 8.82286e-39, 0, 8.82332e-39
vertices[51]: 0, 5.87998e-39, 0
vertices[54]: 5.87998e-39, 0, 8.82286e-39
vertices[57]: 0, -4.13785e+09, 4.58841e-41
vertices[60]: 1.4013e-45, 0, 2.8026e-45
vertices[63]: 0, 8.82195e-39, 0
vertices[66]: 5.88135e-39, 0, 0
vertices[69]: 0, 0, 0
Demo on coliru
So, I just rewrote the loops instead of tediously debugging it. (That appeared the lesser evil to me.)
#include <iostream>
int main()
{
float initTri1[] = { -1.5f, 0.5f, 0.0f, -1.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f };
const size_t nTri1 = std::size(initTri1);
float initTri2[] = { -1.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.5f, 0.0f };
const size_t nTri2 = std::size(initTri2);
const size_t nRect = 4;
const size_t nVtcs = (nTri1 + nTri2) * nRect;
float vertices[nVtcs];
float increment = 0.0f;
for (size_t j = 0, k = 0; j < nRect; ++j) {
for (size_t i = 2; i < nTri1; i += 3) {
vertices[k++] = initTri1[i - 2] + increment;
vertices[k++] = initTri1[i - 1];
vertices[k++] = initTri1[i - 0];
}
for (size_t i = 2; i < nTri2; i += 3) {
vertices[k++] = initTri2[i - 2] + increment;
vertices[k++] = initTri2[i - 1];
vertices[k++] = initTri2[i - 0];
}
increment += 0.5f;
}
for (size_t k = 0; k < nVtcs; ++k) {
if (k % (nTri1 + nTri2) == 0) std::cout << '\n';
if (k % 3 == 0) {
std::cout << "vertices[" << k << "]: ";
}
std::cout << vertices[k];
std::cout << (k % 3 < 2 ? ", " : "\n");
}
}
Output:
vertices[0]: -1.5, 0.5, 0
vertices[3]: -1.5, 0, 0
vertices[6]: -1, 0, 0
vertices[9]: -1.5, 0.5, 0
vertices[12]: -1, 0, 0
vertices[15]: -1, 0.5, 0
vertices[18]: -1, 0.5, 0
vertices[21]: -1, 0, 0
vertices[24]: -0.5, 0, 0
vertices[27]: -1, 0.5, 0
vertices[30]: -0.5, 0, 0
vertices[33]: -0.5, 0.5, 0
vertices[36]: -0.5, 0.5, 0
vertices[39]: -0.5, 0, 0
vertices[42]: 0, 0, 0
vertices[45]: -0.5, 0.5, 0
vertices[48]: 0, 0, 0
vertices[51]: 0, 0.5, 0
vertices[54]: 0, 0.5, 0
vertices[57]: 0, 0, 0
vertices[60]: 0.5, 0, 0
vertices[63]: 0, 0.5, 0
vertices[66]: 0.5, 0, 0
vertices[69]: 0.5, 0.5, 0
Demo on coliru
The moral of the story:
Simpler code is faster to write.
Simpler code is running sooner.
Simpler code is maintenance friendly.
Profiling it, you might be surprised that simpler code might be even faster.
I am trying to create a ring of 8 spike-plates using freeglut. Every plate should be rotated/tilted by 30 degrees relative to the center ball, and all of them are supposed to be ordered in ring-form. Here is an example:
Here is my attempt:
void Larvitar::drawTail()
{
// Create tail ball
glPushMatrix();
glColor4f(0.2, 0, 1, 1.0);
GLUquadric *tail;
tail = gluNewQuadric();
glTranslatef(0, 0.2, -3.0);
gluSphere(tail, 1, 100, 30);
glPopMatrix();
double xrotate = 30;
for (int i = 0; i < 360; i += 45)
{
double rnd = ((double)rand() / (RAND_MAX));
glPushMatrix();
glColor4f(rnd, 0, rnd, 1.0);
glRotatef(xrotate, 1, 0, 0); // kippen?
glRotatef(i, 0, 0, 1); // Kreisform
glScalef(1, 0.4, 2);
glTranslatef(0, -2, -2.1);
glutSolidCube(1);
glPopMatrix();
xrotate -= xrotate;
}
}
The problem is that the plates are in ring form but not each one is tilted by 30 degrees outwards, only the first one is. What am I doing wrong? How can I solve this in a loop without having to create every plate by hand?
Solved it myself.
void Larvitar::drawTail() {
// Create tail ball
glPushMatrix();
glColor4f(0.2, 0, 1, 1.0);
GLUquadric *tail;
tail = gluNewQuadric();
glTranslatef(0, 0.2, -3.0);
gluSphere(tail, 1, 100, 30);
glPopMatrix();
glColor4f(0.58, 0.655, 0.482, 1.0);
for (int i = 0; i < 360; i += 45) {
glPushMatrix();
glRotatef(i, 0, 0, 1);
glRotatef(30, 1, 0, 0);
glScalef(1, 0.5, 2);
glTranslatef(0, -2, -2.1);
glutSolidCube(1);
glPopMatrix();
}
}
I am taking a computer graphics class that teaches us how to use OpenGL with the glut libraries. I have an idea for a final project that involves lighting and textures being put on a dinosaur model that I found online. My first step is to simplify the existing online code so I can begin working on my project.
Unfortunately, the online code for this model is broken, and I cannot seem to figure it out. I am not sure what gluTessCallback does, but my program is very upset with two lines of this code that is making it impossible to run this program on Visual Studio 2012.
Below is the code, and I have indicated which two lines are giving me the trouble.
typedef enum {
RESERVED, BODY_SIDE, BODY_EDGE, BODY_WHOLE, ARM_SIDE, ARM_EDGE, ARM_WHOLE,
LEG_SIDE, LEG_EDGE, LEG_WHOLE, EYE_SIDE, EYE_EDGE, EYE_WHOLE, DINOSAUR
} displayLists;
GLfloat angle = -150; /* in degrees */
GLboolean doubleBuffer = GL_TRUE, iconic = GL_FALSE, keepAspect = GL_FALSE;
int moving, begin;
int W = 300, H = 300;
GLdouble bodyWidth = 2.0;
int newModel = 1;
GLfloat body[][2] = { { 0, 3 },{ 1, 1 },{ 5, 1 },{ 8, 4 },{ 10, 4 },{ 11, 5 },
{ 11, 11.5 },{ 13, 12 },{ 13, 13 },{ 10, 13.5 },{ 13, 14 },{ 13, 15 },{ 11, 16 },
{ 8, 16 },{ 7, 15 },{ 7, 13 },{ 8, 12 },{ 7, 11 },{ 6, 6 },{ 4, 3 },{ 3, 2 },
{ 1, 2 } };
GLfloat arm[][2] = { { 8, 10 },{ 9, 9 },{ 10, 9 },{ 13, 8 },{ 14, 9 },{ 16, 9 },
{ 15, 9.5 },{ 16, 10 },{ 15, 10 },{ 15.5, 11 },{ 14.5, 10 },{ 14, 11 },{ 14, 10 },
{ 13, 9 },{ 11, 11 },{ 9, 11 } };
GLfloat leg[][2] = { { 8, 6 },{ 8, 4 },{ 9, 3 },{ 9, 2 },{ 8, 1 },{ 8, 0.5 },{ 9, 0 },
{ 12, 0 },{ 10, 1 },{ 10, 2 },{ 12, 4 },{ 11, 6 },{ 10, 7 },{ 9, 7 } };
GLfloat eye[][2] = { { 8.75, 15 },{ 9, 14.7 },{ 9.6, 14.7 },{ 10.1, 15 },
{ 9.6, 15.25 },{ 9, 15.25 } };
GLfloat lightZeroPosition[] = { 10.0, 4.0, 10.0, 1.0 };
GLfloat lightZeroColor[] = { 0.8, 1.0, 0.8, 1.0 }; /* green-tinted */
GLfloat lightOnePosition[] = { -1.0, -2.0, 1.0, 0.0 };
GLfloat lightOneColor[] = { 0.6, 0.3, 0.2, 1.0 }; /* red-tinted */
GLfloat skinColor[] = { 0.1, 1.0, 0.1, 1.0 }, eyeColor[] = { 1.0, 0.2, 0.2, 1.0 };
void
extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
{
static GLUtriangulatorObj *tobj = NULL;
GLdouble vertex[3], dx, dy, len;
int i;
int count = dataSize / (int)(2 * sizeof(GLfloat));
if (tobj == NULL) {
tobj = gluNewTess(); /* create and initialize a GLU
polygon tesselation object */
/////////////////////////////////////////////////////////////////////////////////////////
// THESE LINES WILL NOT COMPILE. Says that the glBegin and glVertex2fv are incompatable.
gluTessCallback(tobj, GLU_BEGIN, glBegin);
gluTessCallback(tobj, GLU_VERTEX, glVertex2fv); /* semi-tricky */
/////////////////////////////////////////////////////////////////////////////////////////
gluTessCallback(tobj, GLU_END, glEnd);
}
glNewList(side, GL_COMPILE);
glShadeModel(GL_SMOOTH); /* smooth minimizes seeing
tessellation */
gluBeginPolygon(tobj);
/////////////////////////////////////////////////////////////////////////////////////////
// ALSO A PROBLEM WITH THIS SECTION OF CODE?
for (i = 0; i < count; i++) {
vertex[0] = data[i][0];
vertex[1] = data[i][1];
vertex[2] = 0;
gluTessVertex(tobj, vertex, data[i]);
}
gluEndPolygon(tobj);
glEndList();
/////////////////////////////////////////////////////////////////////////////////////////
glNewList(edge, GL_COMPILE);
glShadeModel(GL_FLAT); /* flat shade keeps angular hands
from being "smoothed" */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= count; i++) {
/* mod function handles closing the edge */
glVertex3f(data[i % count][0], data[i % count][1], 0.0);
glVertex3f(data[i % count][0], data[i % count][1], thickness);
/* Calculate a unit normal by dividing by Euclidean
distance. We * could be lazy and use
glEnable(GL_NORMALIZE) so we could pass in * arbitrary
normals for a very slight performance hit. */
dx = data[(i + 1) % count][1] - data[i % count][1];
dy = data[i % count][0] - data[(i + 1) % count][0];
len = sqrt(dx * dx + dy * dy);
glNormal3f(dx / len, dy / len, 0.0);
}
glEnd();
glEndList();
glNewList(whole, GL_COMPILE);
glFrontFace(GL_CW);
glCallList(edge);
glNormal3f(0.0, 0.0, -1.0); /* constant normal for side */
glCallList(side);
glPushMatrix();
glTranslatef(0.0, 0.0, thickness);
glFrontFace(GL_CCW);
glNormal3f(0.0, 0.0, 1.0); /* opposite normal for other side */
glCallList(side);
glPopMatrix();
glEndList();
}
void
makeDinosaur(void)
{
GLfloat bodyWidth = 3.0;
extrudeSolidFromPolygon(body, sizeof(body), bodyWidth,
BODY_SIDE, BODY_EDGE, BODY_WHOLE);
extrudeSolidFromPolygon(arm, sizeof(arm), bodyWidth / 4,
ARM_SIDE, ARM_EDGE, ARM_WHOLE);
extrudeSolidFromPolygon(leg, sizeof(leg), bodyWidth / 2,
LEG_SIDE, LEG_EDGE, LEG_WHOLE);
extrudeSolidFromPolygon(eye, sizeof(eye), bodyWidth + 0.2,
EYE_SIDE, EYE_EDGE, EYE_WHOLE);
glNewList(DINOSAUR, GL_COMPILE);
glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
glCallList(BODY_WHOLE);
glPushMatrix();
glTranslatef(0.0, 0.0, bodyWidth);
glCallList(ARM_WHOLE);
glCallList(LEG_WHOLE);
glTranslatef(0.0, 0.0, -bodyWidth - bodyWidth / 4);
glCallList(ARM_WHOLE);
glTranslatef(0.0, 0.0, -bodyWidth / 4);
glCallList(LEG_WHOLE);
glTranslatef(0.0, 0.0, bodyWidth / 2 - 0.1);
glMaterialfv(GL_FRONT, GL_DIFFUSE, eyeColor);
glCallList(EYE_WHOLE);
glPopMatrix();
glEndList();
}
void
recalcModelView(void)
{
glPopMatrix();
glPushMatrix();
glRotatef(angle, 0.0, 1.0, 0.0);
glTranslatef(-8, -8, -bodyWidth / 2);
newModel = 0;
}
void
redraw(void)
{
if (newModel)
recalcModelView();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glCallList(DINOSAUR);
glutSwapBuffers();
}
/* ARGSUSED2 */
void
mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
moving = 1;
begin = x;
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
moving = 0;
}
}
/* ARGSUSED1 */
void
motion(int x, int y)
{
if (moving) {
angle = angle + (x - begin);
begin = x;
newModel = 1;
glutPostRedisplay();
}
}
GLboolean lightZeroSwitch = GL_TRUE, lightOneSwitch = GL_TRUE;
void
controlLights(int value)
{
switch (value) {
case 1:
lightZeroSwitch = !lightZeroSwitch;
if (lightZeroSwitch) {
glEnable(GL_LIGHT0);
}
else {
glDisable(GL_LIGHT0);
}
break;
case 2:
lightOneSwitch = !lightOneSwitch;
if (lightOneSwitch) {
glEnable(GL_LIGHT1);
}
else {
glDisable(GL_LIGHT1);
}
break;
}
glutPostRedisplay();
}
int
main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("glutdino");
glutDisplayFunc(redraw);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutCreateMenu(controlLights);
glutAddMenuEntry("Toggle right light", 1);
glutAddMenuEntry("Toggle left light", 2);
glutAttachMenu(GLUT_RIGHT_BUTTON);
makeDinosaur();
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glMatrixMode(GL_PROJECTION);
gluPerspective( /* field of view in degree */ 40.0,
/* aspect ratio */ 1.0,
/* Z near */ 1.0, /* Z far */ 40.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(0.0, 0.0, 30.0, /* eye is at (0,0,30) */
0.0, 0.0, 0.0, /* center is at (0,0,0) */
0.0, 1.0, 0.); /* up is in postivie Y direction */
glPushMatrix(); /* dummy push so we can pop on model
recalc */
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition);
glLightfv(GL_LIGHT1, GL_DIFFUSE, lightOneColor);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
glutMainLoop();
return 0; /* ANSI C requires main to return int. */
}
I tried to make it clear where the problem is. OpenGl is bringing me to my wit's end. Is there nowhere I can get a simple 3D dinosaur model to play with on the internet?
I hope you can provide me some insight on this gluTessCallback issue so I can get this working. All I want is a solid dinosaur model.
Looking at the man page, the signature of the callback passed to gluTessCallback() depends on the enum value passed as the second argument. This means that if you're using C++, or a version of C that uses function prototypes, you will need a typecast to cast your function to the type expected by gluTessCallback().
According to the man page, the argument type is defined as _GLUfuncptr. However, that type is not defined in the glu.h header I found. The type according to the spec and header is a function with no arguments and a return type of GLvoid. You can define your own function type for this, and then cast to it:
typedef GLvoid (*TessFuncPtr)();
gluTessCallback(tobj, GLU_BEGIN, (TessFuncPtr)glBegin);
gluTessCallback(tobj, GLU_VERTEX, (TessFuncPtr)glVertex2fv);
If you're just learning OpenGL, you should be aware that almost all of the calls in this code are deprecated and obsolete. This includes:
Immediate mode rendering (glBegin, glEnd, etc).
Display lists.
Matrix stack.
Fixed function lighting and material definitions.
I think you would be much better off learning a current version of OpenGL. For example the tessellation functionality you are trying to use was defined close to 25 years ago. Aside from being deprecated, I don't think it was ever widely used in the first place.
I am making changes in the code from this article, to acomplish the same result without need the methods specific for Windows and be able to run the programa in other platforms. I can compile and run the program without errors (with the Main and Render functions listed below), but the result is a blank screen. Someone can find some reason in the code for this issue happen?
Main:
int main(int argc, char **argv)
{
// temp var's
int width = 800;
int height = 600;
int bits = 32;
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(width,height);
glutInit(&argc, argv);
glutCreateWindow("Terrain");
glutDisplayFunc(Render);
glutReshapeFunc(AlteraTamanhoJanela);
glutKeyboardFunc(GerenciaTeclado);
glutMouseFunc(GerenciaMouse);
Initialize();
glutMainLoop();
}
Render:
void Render()
{
radians = float(PI*(angle-90.0f)/180.0f);
// calculate the camera's position
cameraX = lookX + sin(radians)*mouseY; // multiplying by mouseY makes the
cameraZ = lookZ + cos(radians)*mouseY; // camera get closer/farther away with mouseY
cameraY = lookY + mouseY / 2.0f;
// calculate the camera look-at coordinates as the center of the terrain map
lookX = (MAP_X*MAP_SCALE)/2.0f;
lookY = 150.0f;
lookZ = -(MAP_Z*MAP_SCALE)/2.0f;
// clear screen and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// set the camera position
gluLookAt(cameraX, cameraY, cameraZ, lookX, lookY, lookZ, 0.0, 1.0, 0.0);
// set the current texture to the land texture
glBindTexture(GL_TEXTURE_2D, land);
// we are going to loop through all of our terrain's data points,
// but we only want to draw one triangle strip for each set along the x-axis.
for (int z = 0; z < MAP_Z-1; z++)
{
//printf("%s %d\n","Loop FOR para Z = ",z);
glBegin(GL_TRIANGLE_STRIP);
for (int x = 0; x < MAP_X-1; x++)
{
//printf("%s %d\n","Loop FOR para X = ",x);
// for each vertex, we calculate the grayscale shade color,
// we set the texture coordinate, and we draw the vertex.
/*
the vertices are drawn in this order:
0 ---> 1
/
/
|/
2 ---> 3
*/
// draw vertex 0
//printf("%s\n","Primeiro");
glColor3f(terrain[x][z][1]/255.0f, terrain[x][z][1]/255.0f, terrain[x][z][1]/255.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(terrain[x][z][0], terrain[x][z][1], terrain[x][z][2]);
// draw vertex 1
//printf("%s\n","Segundo");
glTexCoord2f(1.0f, 0.0f);
glColor3f(terrain[x+1][z][1]/255.0f, terrain[x+1][z][1]/255.0f, terrain[x+1][z][1]/255.0f);
glVertex3f(terrain[x+1][z][0], terrain[x+1][z][1], terrain[x+1][z][2]);
// draw vertex 2
//printf("%s\n","Terceiro");
glTexCoord2f(0.0f, 1.0f);
glColor3f(terrain[x][z+1][1]/255.0f, terrain[x][z+1][1]/255.0f, terrain[x][z+1][1]/255.0f);
glVertex3f(terrain[x][z+1][0], terrain[x][z+1][1], terrain[x][z+1][2]);
// draw vertex 3
//printf("%s\n","Quarto");
glColor3f(terrain[x+1][z+1][1]/255.0f, terrain[x+1][z+1][1]/255.0f, terrain[x+1][z+1][1]/255.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(terrain[x+1][z+1][0], terrain[x+1][z+1][1], terrain[x+1][z+1][2]);
}
glEnd();
}
// enable blending
glEnable(GL_BLEND);
// enable read-only depth buffer
glDepthMask(GL_FALSE);
// set the blend function to what we use for transparency
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
// set back to normal depth buffer mode (writable)
glDepthMask(GL_TRUE);
// disable blending
glDisable(GL_BLEND);
glFlush();
//SwapBuffers(g_HDC); // bring backbuffer to foreground
}
Update: As requested, here is the other functions from my code.
void InitializeTerrain()
{
// loop through all of the heightfield points, calculating
// the coordinates for each point
for (int z = 0; z < MAP_Z; z++)
{
for (int x = 0; x < MAP_X; x++)
{
terrain[x][z][0] = float(x)*MAP_SCALE;
terrain[x][z][1] = (float)imageData[(z*MAP_Z+x)*3];
terrain[x][z][2] = -float(z)*MAP_SCALE;
}
}
}
void CleanUp()
{
free(imageData);
free(landTexture);
}
// Initialize
// desc: initializes OpenGL
void Initialize()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // clear to black
glShadeModel(GL_SMOOTH); // use smooth shading
glEnable(GL_DEPTH_TEST); // hidden surface removal
glEnable(GL_CULL_FACE); // do not calculate inside of poly's
glFrontFace(GL_CCW); // counter clock-wise polygons are out
glEnable(GL_TEXTURE_2D); // enable 2D texturing
imageData = LoadBitmapFile("terrain2.bmp", &bitmapInfoHeader);
// initialize the terrain data and load the textures
InitializeTerrain();
LoadTextures();
}
// Função callback chamada quando o tamanho da janela é alterado
void AlteraTamanhoJanela(GLsizei w, GLsizei h)
{
int width, height;
height = h; // retrieve width and height
width = w;
if (height==0) // don't want a divide by zero
{
height=1;
}
glViewport(0, 0, width, height); // reset the viewport to new dimensions
glMatrixMode(GL_PROJECTION); // set projection matrix current matrix
glLoadIdentity(); // reset projection matrix
// calculate aspect ratio of window
gluPerspective(54.0f,(GLfloat)width/(GLfloat)height,1.0f,1000.0f);
glMatrixMode(GL_MODELVIEW); // set modelview matrix
glLoadIdentity(); // reset modelview matrix
}
// Função callback chamada para gerenciar eventos do mouse
void GerenciaMouse(int button, int state, int x, int y)
{
int oldMouseX, oldMouseY;
// save old mouse coordinates
oldMouseX = mouseX;
oldMouseY = mouseY;
// get mouse coordinates from Windows
mouseX = x;
mouseY = y;
// these lines limit the camera's range
if (mouseY < 200)
mouseY = 200;
if (mouseY > 450)
mouseY = 450;
if ((mouseX - oldMouseX) > 0) // mouse moved to the right
angle += 3.0f;
else if ((mouseX - oldMouseX) < 0) // mouse moved to the left
angle -= 3.0f;
glutPostRedisplay();
}
/* Key press processing */
void GerenciaTeclado(unsigned char c, int x, int y)
{
if(c == 27) exit(0);
}
And, finally, the content from file vkgllib.h, included by source code file above:
#include <iostream>
#include <fstream>
#include <math.h>
#include <stdlib.h>
using namespace std;
#define WINDOW_WIDTH 640 // Window Width Default
#define WINDOW_HEIGHT 480 // Window Height Default
// definition of PI
#define PI 3.14159265
// Used to defien the title of the window
#define WINDOW_TITLE "OpenGL Terrain Generation"
// A simple structure to define a point whose coordinates are integers
/*typedef struct { GLint x, y; } GLintPoint;
// This structure is used to store the vertices of a polyline
typedef struct { int num; GLintPoint pt[100]; } GLintPointArray;
// Data for an Icosahedron
#define ICO_X 0.525731112119133606
#define ICO_Z 0.850650808352039932*/
/*static GLfloat vdataICO[12][3] =
{
{ -ICO_X, 0.0, ICO_Z }, { ICO_X, 0.0, ICO_Z }, { -ICO_X, 0.0, -ICO_Z }, { ICO_X, 0.0, -ICO_Z },
{ 0.0, ICO_Z, ICO_X }, { 0.0, ICO_Z, -ICO_X }, { 0.0, -ICO_Z, ICO_X }, { 0.0, -ICO_Z, -ICO_X },
{ ICO_Z, ICO_X, 0.0 }, { -ICO_Z, ICO_X, 0.0 }, { ICO_Z, -ICO_X, 0.0 }, { -ICO_Z, -ICO_X, 0.0 }
};
static GLuint tindicesICO[20][3] =
{
{ 1, 4, 0 }, { 4, 9, 0 }, { 4, 5, 9 }, { 8, 5, 4 }, { 1, 8, 4 },
{ 1, 10, 8 }, { 10, 3, 8 }, { 8, 3, 5 }, { 3, 2, 5 }, { 3, 7, 2 },
{ 3, 10, 7 }, { 10, 6, 7 }, { 6, 11, 7 }, { 6, 0, 11 }, {6, 1, 0 },
{ 10, 1, 6 }, { 11, 0, 9 }, { 2, 11, 9 }, { 5, 2, 9 }, { 11, 2, 7 }
};*/
// Data for Tetrahedron
static GLfloat P1T[3] = { -2, 3, 0 };
static GLfloat P2T[3] = { -3, 0, 0 };
static GLfloat P3T[3] = { -1, 0, 3 };
static GLfloat P4T[3] = { -4, 0, 0 };
// Calculating the Normalized Cross Product of Two Vectors
void normalize( float v[3] )
{
GLfloat d = sqrt( float(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]) );
if( d==0.0 )
{
cerr<<"zero length vector"<<endl;
return;
}
v[0] /= d;
v[1] /= d;
v[2] /= d;
}
void normcrossprod( float v1[3], float v2[3], float out[3] )
{
out[0] = v1[1]*v2[2] - v1[2]*v2[1];
out[1] = v1[2]*v2[0] - v1[0]*v2[2];
out[2] = v1[0]*v2[1] - v1[1]*v2[0];
normalize( out );
}
////// Defines
#define BITMAP_ID 0x4D42 // the universal bitmap ID
#define MAP_X 32 // size of map along x-axis
#define MAP_Z 32 // size of map along z-axis
#define MAP_SCALE 20.0f // the scale of the terrain map
////// Texture Information
BITMAPINFOHEADER bitmapInfoHeader; // temp bitmap info header
BITMAPINFOHEADER landInfo; // land texture info header
BITMAPINFOHEADER waterInfo; // water texture info header
//AUX_RGBImageRec
unsigned char* imageData; // the map image data
unsigned char* landTexture; // land texture data
unsigned int land; // the land texture object
////// Terrain Data
float terrain[MAP_X][MAP_Z][3]; // heightfield terrain data (0-255); 256x256
// LoadBitmapFile
// desc: Returns a pointer to the bitmap image of the bitmap specified
// by filename. Also returns the bitmap header information.
// No support for 8-bit bitmaps.
unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader)
{
FILE *filePtr; // the file pointer
BITMAPFILEHEADER bitmapFileHeader; // bitmap file header
unsigned char *bitmapImage; // bitmap image data
int imageIdx = 0; // image index counter
unsigned char tempRGB; // swap variable
// open filename in "read binary" mode
filePtr = fopen(filename, "rb");
if (filePtr == NULL)
return NULL;
// read the bitmap file header
fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
// verify that this is a bitmap by checking for the universal bitmap id
if (bitmapFileHeader.bfType != BITMAP_ID)
{
fclose(filePtr);
return NULL;
}
// read the bitmap information header
fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
// move file pointer to beginning of bitmap data
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
// allocate enough memory for the bitmap image data
bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);
// verify memory allocation
if (!bitmapImage)
{
free(bitmapImage);
fclose(filePtr);
return NULL;
}
// read in the bitmap image data
fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);
// make sure bitmap image data was read
if (bitmapImage == NULL)
{
fclose(filePtr);
return NULL;
}
// swap the R and B values to get RGB since the bitmap color format is in BGR
for (imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx+=3)
{
tempRGB = bitmapImage[imageIdx];
bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
bitmapImage[imageIdx + 2] = tempRGB;
}
// close the file and return the bitmap image data
fclose(filePtr);
return bitmapImage;
}
bool LoadTextures()
{
// load the land texture data
landTexture = LoadBitmapFile("green.bmp", &landInfo);
if (!landTexture)
return false;
// generate the land texture as a mipmap
glGenTextures(1, &land);
glBindTexture(GL_TEXTURE_2D, land);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, landInfo.biHeight, landInfo.biWidth, GL_RGB, GL_UNSIGNED_BYTE, landTexture);
return true;
}
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
^^^^^^^^^^^
You've asked for double-buffering.
And yet your Render() function seems to assume you're using single-buffering:
void Render()
{
...
glFlush();
}
Either switch to GLUT_SINGLE or use glutSwapBuffers() instead of glFlush().