OpenGL sample particle simulation doesnt show up particles - visual-c++
I have created a simple particle simulation for a fountain from this source. I also wanted to implement this using C++ classes. So, tried to put the above part of the logic into classes at this source (This is a very nice framework). I just have to inherit the class and redefine the functionalities that I would like.
I defined the functions for display() in which I call my DrawObjects().
I am running into the following issues:
I am initializing the number of particles to as low as 50 or 100 or 500. Nothing visible.
I am trying to load a texture(BMP) for my particles. It is failing for some reason. I tried both relative and absolute paths. Then tried to load a RAW texture(using IrfanViewer) with no luck. Also tried to remove the texture code to make them simple OpenGL primitives. Again no luck.
I wrote a simple DrawAxis() function which actually needs to draw cyan colored axis with red colored strings. However, gray colored primitives are showing up. I checked the code for usage of grayscale configuration, but no such thing.
Note: Working on Windows VC++ 2010. Code can be found at NippyZip.
Minimal Code
Main.cpp
#include "ParticleSimulation.h"
int main(int argc, char *argv[]) {
ParticleSimulation particleSimulation(50);
particleSimulation.InitParticles();
particleSimulation.setLookAt(80.0, 80.0, 80.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
particleSimulation.startFramework(argc, argv);
// **Note** No code below startFramework() will get executed
return 0;
}
GlutFramework.cpp
#include "GlutFramework.h"
namespace glutFramework {
// Set constants
const double GlutFramework::FRAME_TIME = 1.0 / GlutFramework::FPS * 1000.0; // Milliseconds
GlutFramework *GlutFramework::instance = NULL;
GlutFramework::GlutFramework() {
elapsedTimeInSeconds = 0;
frameTimeElapsed = 0;
title = "GLUT Framework: Paul Solt 2010";
eyeVector = Vector<float>(0.0, 0.0, -10.0); // move the eye position back
position = 0.0f;
direction = 1.0 / FRAME_TIME;
}
GlutFramework::~GlutFramework() {
}
void GlutFramework::startFramework(int argc, char *argv[]) {
setInstance(); // Sets the instance to self, used in the callback wrapper functions
// Initialize GLUT
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(WINDOW_X_POSITION, WINDOW_Y_POSITION);
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
glutCreateWindow(title.c_str());
// Function callbacks with wrapper functions
glutReshapeFunc(reshapeWrapper);
glutMouseFunc(mouseButtonPressWrapper);
glutMotionFunc(mouseMoveWrapper);
glutDisplayFunc(displayWrapper);
glutKeyboardFunc(keyboardDownWrapper);
glutKeyboardUpFunc(keyboardUpWrapper);
glutSpecialFunc(specialKeyboardDownWrapper);
glutSpecialUpFunc(specialKeyboardUpWrapper);
init(); // Initialize
glutIdleFunc(runWrapper); // The program run loop
glutMainLoop(); // Start the main GLUT thread
}
void GlutFramework::load() {
// Subclass and override this method
}
void GlutFramework::display(float dTime) {
// Subclass and override this method
static int frame = 0;
std::cout << "GlutFramework Display: Frame: " << frame << ", dt(sec): " << dTime << ", Position: " << position << std::endl;
++frame;
// DEMO: Create a teapot and move it back and forth on the x-axis
glTranslatef(position, 0.0f, 0.0f);
glutSolidTeapot(2.5);
if(position > 4 && direction > 0) {
direction = -1.0 / FRAME_TIME;
} else if(position < -4 && direction < 0) {
direction = 1.0 / FRAME_TIME;
}
position += direction;
}
void GlutFramework::reshape(int width, int height) {
glViewport(0,0,(GLsizei)width,(GLsizei)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, (GLdouble) width, 0.0, (GLdouble) height);
}
void GlutFramework::mouseButtonPress(int button, int state, int x, int y) {
printf("MouseButtonPress: x: %d y: %d\n", x, y);
}
void GlutFramework::mouseMove(int x, int y) {
printf("MouseMove: x: %d y: %d\n", x, y);
}
void GlutFramework::keyboardDown( unsigned char key, int x, int y )
{
// Subclass and override this method
printf( "KeyboardDown: %c = %d\n", key, (int)key );
if (key==27) { //27 =- ESC key
exit (0);
}
keyStates.keyDown( (int)key );
}
void GlutFramework::keyboardUp( unsigned char key, int x, int y )
{
// Subclass and override this method
printf( "KeyboardUp: %c \n", key );
keyStates.keyUp( (int)key );
}
void GlutFramework::specialKeyboardDown( int key, int x, int y )
{
// Subclass and override this method
printf( "SpecialKeyboardDown: %d\n", key );
}
void GlutFramework::specialKeyboardUp( int key, int x, int y )
{
// Subclass and override this method
printf( "SpecialKeyboardUp: %d \n", key );
}
// ******************************
// ** Graphics helper routines **
// ******************************
// Initialize the projection/view matricies.
void GlutFramework::setDisplayMatricies() {
/* Setup the projection and model view matricies */
int width = glutGet( GLUT_WINDOW_WIDTH );
int height = glutGet( GLUT_WINDOW_HEIGHT );
float aspectRatio = width/height;
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 60, aspectRatio, 1, 500.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
gluLookAt(eyeVector.x, eyeVector.y, eyeVector.z,
centerVector.x, centerVector.y, centerVector.z,
upVector.x, upVector.y, upVector.z);
}
void GlutFramework::setupLights() {
GLfloat light1_position[] = { 0.0, 1.0, 1.0, 0.0 };
GLfloat white_light[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat lmodel_ambient[] = { 0.4, 0.4, 0.4, 1.0 };
GLfloat ambient_light[] = { 0.8, 0.8, 0.8, 1.0 };
glLightfv( GL_LIGHT0, GL_POSITION, light1_position );
glLightfv( GL_LIGHT0, GL_AMBIENT, ambient_light );
glLightfv( GL_LIGHT0, GL_DIFFUSE, white_light );
glLightfv( GL_LIGHT0, GL_SPECULAR, white_light );
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );
}
void GlutFramework::setLookAt(float eyeX, float eyeY, float eyeZ,
float centerX, float centerY, float centerZ, float upX, float upY, float upZ) {
eyeVector = Vector<float>(eyeX, eyeY, eyeZ);
centerVector = Vector<float>(centerX, centerY, centerZ);
upVector = Vector<float>(upX, upY, upZ);
}
Vector<float> GlutFramework::getEyeVector() const {
return eyeVector;
}
Vector<float> GlutFramework::getCenterVector() const {
return centerVector;
}
Vector<float> GlutFramework::getUpVector() const {
return upVector;
}
void GlutFramework::setTitle(std::string theTitle) {
title = theTitle;
}
// **************************
// ** GLUT Setup functions **
// **************************
void GlutFramework::init() {
glClearColor(0.0, 0.0, 0.0, 1.0);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
load();
}
void GlutFramework::setInstance() {
//std::cout << "GlutFramework::setInstance()" << std::endl;
instance = this;
}
void GlutFramework::run() {
if(frameRateTimer.isStopped()) { // The initial frame has the timer stopped, start it once
frameRateTimer.start();
}
frameRateTimer.stop(); // stop the timer and calculate time since last frame
double milliseconds = frameRateTimer.getElapsedMilliseconds();
frameTimeElapsed += milliseconds;
if( frameTimeElapsed >= FRAME_TIME ) { // If the time exceeds a certain "frame rate" then show the next frame
glutPostRedisplay();
frameTimeElapsed -= FRAME_TIME; // remove a "frame" and start counting up again
}
frameRateTimer.start(); // start the timer
}
void GlutFramework::displayFramework() {
if(displayTimer.isStopped()) { // Start the timer on the initial frame
displayTimer.start();
}
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // Clear once
displayTimer.stop(); // Stop the timer and get the elapsed time in seconds
elapsedTimeInSeconds = displayTimer.getElapsedSeconds(); // seconds
setupLights();
setDisplayMatricies();
display(elapsedTimeInSeconds);
glutSwapBuffers();
displayTimer.start(); // reset the timer to calculate the time for the next frame
}
// ******************************************************************
// ** Static functions which are passed to Glut function callbacks **
// ******************************************************************
void GlutFramework::displayWrapper() {
instance->displayFramework();
}
void GlutFramework::reshapeWrapper(int width, int height) {
instance->reshape(width, height);
}
void GlutFramework::runWrapper() {
instance->run();
}
void GlutFramework::mouseButtonPressWrapper(int button, int state, int x, int y) {
instance->mouseButtonPress(button, state, x, y);
}
void GlutFramework::mouseMoveWrapper(int x, int y) {
instance->mouseMove(x, y);
}
void GlutFramework::keyboardDownWrapper(unsigned char key, int x, int y) {
instance->keyboardDown(key,x,y);
}
void GlutFramework::keyboardUpWrapper(unsigned char key, int x, int y) {
instance->keyboardUp(key,x,y);
}
void GlutFramework::specialKeyboardDownWrapper(int key, int x, int y) {
instance->specialKeyboardDown(key,x,y);
}
void GlutFramework::specialKeyboardUpWrapper(int key, int x, int y) {
instance->specialKeyboardUp(key,x,y);
}
} // namespace
ParticleSimulation.h
#include "preheader.h"
#include "Particle.h"
#include "GlutFramework.h"
#ifndef ___PARTICLESIMULATION_H___
#define ___PARTICLESIMULATION_H___
using namespace glutFramework;
#ifndef ABS_IMAGE_LOCATION
#define ABS_IMAGE_LOCATION "E:/IIIT B/College/Sem 3/CG/GraphicAssignment3/images/particle.bmp"
#endif
class ParticleSimulation : virtual public GlutFramework{
private:
GLuint numParticles; // total number of particles in the system
Particle *particles;
GLuint textureParticle;
//static GLint textureCount;
//functions
void AllocateObjects(void );
void DeAllocateObjects(void );
public:
ParticleSimulation(void );
ParticleSimulation(GLuint numParticles);
~ParticleSimulation(void );
void InitParticles(void );
void EvolveParticle(void );
void DisplayObjects(void );
void LoadTextureRAW(const char * filename, int wrap);
void LoadTextureBMP(const char * filename, int wrap);
void FreeTexture(void );
void DrawAxis();
void RenderBitmapString(GLfloat x, GLfloat y, GLfloat z, void *font, char *string);
//virtual functions
void display(float dTime);
};
#endif //___PARTICLESIMULATION_H___
ParticleSimulation.cpp
#include "ParticleSimulation.h"
using namespace std;
. . .
void ParticleSimulation::DisplayObjects(){
// rendering functions
glLoadIdentity();
//glRotatef(20.0, 1.0, 0.0, 0.0); // show scene from top front
//glBindTexture(GL_TEXTURE_2D, this->textureParticle); // choose particle texture
for (int i = 0; i <= this->numParticles; i++){
GLfloat xpos = 0.0f, ypos = 0.0f, zpos = 0.0f;
particles[i].getPosition(xpos, ypos, zpos);
if(ypos < 0.0)
particles[i].setLifeTime(0.0);
if(particles[i].getActiveStatus() && particles[i].getLifeTime() > 0.0) {
GLfloat red = 0.0f, green = 0.0f, blue = 0.0f;
particles[i].getColor(red, green, blue);
glColor3f(red, green, blue);
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(0.0,1.0); glVertex3f(xpos + 0.002, ypos + 0.002, zpos + 0.0); // top right
glVertex2f(0.0,0.0); glVertex3f(xpos - 0.002, ypos + 0.002, zpos + 0.0); // top left
glVertex2f(1.0,1.0); glVertex3f(xpos + 0.002, ypos - 0.002, zpos + 0.0); // bottom right
glVertex2f(1.0,0.0); glVertex3f(xpos - 0.002, ypos - 0.002, zpos + 0.0); // bottom left
//glTexCoord2f(1.0,0.0); glVertex3f(xpos - 0.002, ypos - 0.002, zpos + 0.0); // bottom left
glEnd();
} else {
particles[i].CreateParticle();
}
}
EvolveParticle();
}
void ParticleSimulation::EvolveParticle()
{
for(int i = 0; i <= this->numParticles; i++){ // evolve the particle parameters
GLfloat xpos = 0.0f, ypos = 0.0f, zpos = 0.0f;
GLfloat green = 0.0f, red = 0.0f, blue = 0.0f;
GLfloat xVel = 0.0f, yVel = 0.0f, zVel = 0.0f;
particles[i].setLifeTime( particles[i].getLifeTime() - particles[i].getDecay() );
particles[i].getPosition(xpos, ypos, zpos);
particles[i].getSpeed(xVel, yVel, zVel);
particles[i].getPosition(xpos += xVel, ypos += yVel, zpos += zVel);
particles[i].getSpeed(xVel, yVel -= 0.00007, zVel);
}
}
// Texture ///////////////////////////////////////////////////////////
// load a 256x256 RGB .RAW file as a texture
void ParticleSimulation::LoadTextureBMP(const char * filename, int wrap)
{
int width = 0, height = 0;
BYTE *data = NULL;
FILE *file = NULL;
// open texture data
file = fopen( filename, "rb" );
if ( file == NULL ) {
cout << "\nFile could not be opened." << endl;
return;
}
// allocate buffer
width = 256;
height = 256;
data = (BYTE *) malloc( width * height * 3 );
// read texture data
fread( data, width * height * 3, 1, file );
fclose(file);
// allocate a texture name
this->textureParticle = 0;
glGenTextures( 1, &this->textureParticle );
// select our current texture
glBindTexture( GL_TEXTURE_2D, this->textureParticle );
// select modulate to mix texture with color for shading
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// when texture area is small, bilinear filter the closest MIP map
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST );
// when texture area is large, bilinear filter the first MIP map
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// if wrap is true, the texture wraps over at the edges (repeat)
// ... false, the texture ends at the edges (clamp)
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
wrap ? GL_REPEAT : GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
wrap ? GL_REPEAT : GL_CLAMP );
// build our texture MIP maps
gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width,
height, GL_RGB, GL_UNSIGNED_BYTE, data );
// free buffer
free( data );
return;
}
void ParticleSimulation::FreeTexture(void )
{
glDeleteTextures(1, &this->textureParticle);
}
void ParticleSimulation::DrawAxis() {
char s1[10];
glPushMatrix();
glColor3f(1.0f, 0.0f, 0.0f);
sprintf(s1, "X-axis");
RenderBitmapString(50.0f, 0.0f, 0.0f, GLUT_BITMAP_HELVETICA_12, s1);
sprintf(s1, "Y-axis");
RenderBitmapString(0.0f, 50.0f, 0.0f, GLUT_BITMAP_HELVETICA_12, s1);
sprintf(s1, "Z-axis");
RenderBitmapString(0.0f, 0.0f, 50.0f, GLUT_BITMAP_HELVETICA_12, s1);
sprintf(s1, "Origin");
RenderBitmapString(0.0f, 0.0f, 0.0f, GLUT_BITMAP_HELVETICA_12, s1);
glPointSize(4.0f);
glColor3f(0.0f, 1.0f, 1.0f);
glBegin(GL_LINE_STRIP);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 50.0f, 0.0f);
glEnd();
glBegin(GL_LINE_STRIP);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(50.0f, 0.0f, 0.0f);
glEnd();
glBegin(GL_LINE_STRIP);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 50.0f);
glEnd();
glPopMatrix();
}
void ParticleSimulation::display(float dTime)
{
static int frame = 0;
//cout << "GlutFramework Display: Frame: " << frame << ", dt(sec): " << dTime << ", Position: " << position << endl;
++frame;
//cout << "Calling the DisplayObject Function" << endl;
//glTranslatef(0.0f, 0.0f, 0.0f);
//glutSolidTeapot(2.5);
DrawAxis(); //Aditya: Working with grayscale though
DisplayObjects(); //Aditya: Nothing is drawn
}
LoadTextureBMP() is being invoked (with its bevy of OpenGL calls) before you have an OpenGL context (via startFramework()).
You need a current context before issuing GL commands.
EDIT:
for(int i = 0; i <= this->numParticles; i++)
Stop that. You're accessing off the end of your allocated memory.
Do this:
for(int i = 0; i < this->numParticles; i++)
Notice the less-than instead of the less-than-or-equal. For C/C++ arrays of size N the only valid indexes are in the range [0, N-1]. Your <= will cause the for-loop to try to access element N.
That's bad.
EDIT2:
GlutFramework::init() enables lighting. This is altering the colors in your axis rendering in ParticleSimulation::DrawAxis(). Disable it in ParticleSimulation::display() via glDisable(GL_LIGHTING):
EDIT3:
This will do something but probably not what you expect:
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(0.0,1.0); glVertex3f(xpos + 0.002, ypos + 0.002, zpos + 0.0); // top right
glVertex2f(0.0,0.0); glVertex3f(xpos - 0.002, ypos + 0.002, zpos + 0.0); // top left
glVertex2f(1.0,1.0); glVertex3f(xpos + 0.002, ypos - 0.002, zpos + 0.0); // bottom right
glVertex2f(1.0,0.0); glVertex3f(xpos - 0.002, ypos - 0.002, zpos + 0.0); // bottom left
glEnd();
You seem to think that glVertex2f() will somehow generate texture coordinates. It will not. You're looking for glTexCoord2f().
For drawing view-aligned triangles you'll want to look into billboarding.
Related
After XResizeWindow, new window content drawn is not displayed
I'm writing an application in Linux using Xlib to manage a window and cairo to draw some text in it. The text content of the window changes during the execution, so I want to adapt the window size to match that of the text extent. If the size of the text extent does not change, the window is always correctly updated with the new text. But when the text extent changes, and so the window is resized accordingly, the window is cleared but the new text is never shown. Only if there is no call to XResizeWindow the text is actually displayed. The code I'm using is if (/* Text extent is changed */) { XResizeWindow (display, window, new_width, new_height); cairo_xlib_surface_set_size (surface, new_width, new_height); } XClearWindow (display, window); /* ... Cairo code to draw the text ... */ // cairo_surface_flush (surface); // XFlush (display); I have also tried to add after the Cairo code that draws the text the methods cairo_surface_flush and XFlush (commented in the example) but nothing changes. EDIT: I solved the problem using two threads: the first thread with the usual loop for listening to the Expose events plus the code to redraw the content and the second thread that issues the resize of the window and sends an Expose event to wake up the first thread. In this example the window is resized every 500 ms to random width and height and a progressive counter is displayed in it at every resize. I use C++11, compile with: g++ -std=c++11 -o test test.cpp -lX11 -lcairo -lpthread The code is: #include <random> #include <chrono> #include <thread> #include <string> #include <X11/Xlib.h> #include <cairo/cairo-xlib.h> Display * d; Window w; cairo_surface_t * surface; int width = 300, height = 300; unsigned char counter = 0; std::random_device rd; std::knuth_b gen (rd ()); std::uniform_int_distribution < > dist (150, 300); void logic () { XEvent send_event; send_event.type = Expose; send_event.xexpose.window = w; while (true) { std::this_thread::sleep_for (std::chrono::milliseconds (500)); ++ counter; width = dist (gen); height = dist (gen); cairo_xlib_surface_set_size (surface, width, height); XResizeWindow (d, w, width, height); XSendEvent (d, w, False, ExposureMask, & send_event); XFlush (d); } } int main ( ) { XInitThreads (); d = XOpenDisplay (NULL); w = XCreateSimpleWindow (d, RootWindow (d, 0), 0, 0, width, height, 0, 0, 0x000000); XMapWindow (d, w); XSelectInput (d, w, ExposureMask | KeyPressMask); surface = cairo_xlib_surface_create (d, w, DefaultVisual (d, 0), width, height); cairo_t * cairo = cairo_create (surface); cairo_select_font_face (cairo, "FreeSans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size (cairo, 40 ); cairo_set_source_rgb (cairo, 0.8, 0.8, 0.8); cairo_move_to (cairo, 40.0, 60.0); cairo_show_text (cairo, std::to_string (counter).c_str ()); XFlush (d); std::thread T (logic); XEvent event; while (true) { XNextEvent (d, & event); if (event.type == Expose) { XClearWindow (d, w); cairo_move_to (cairo, 40.0, 60.0); cairo_show_text (cairo, std::to_string (counter).c_str ()); } else if (event.type == KeyPress) { XCloseDisplay (d); return 0; } } } But a question remains: is it possible to obtain the same result using only one thread?
Here is a single-threaded version of your code. It is not nice, but it seems to work. The hard part is waiting for events from the X11 server and the timeout simultaneously. I do this with select() in the following code. Note that I also handle ConfigureNotify events instead of assuming that XResizeWindow always does just what we want. #include <random> #include <chrono> #include <thread> #include <string> #include <X11/Xlib.h> #include <cairo/cairo-xlib.h> #include <sys/time.h> Display * d; Window w; cairo_surface_t * surface; int width = 300, height = 300; unsigned char counter = 0; std::random_device rd; std::knuth_b gen (rd ()); std::uniform_int_distribution < > dist (150, 300); void do_update () { ++ counter; width = dist (gen); height = dist (gen); XResizeWindow (d, w, width, height); // Force a redraw XClearArea(d, w, 0, 0, 0, 0, True); } int main ( ) { XInitThreads (); d = XOpenDisplay (NULL); w = XCreateSimpleWindow (d, RootWindow (d, 0), 0, 0, width, height, 0, 0, 0x000000); XMapWindow (d, w); XSelectInput (d, w, ExposureMask | KeyPressMask); surface = cairo_xlib_surface_create (d, w, DefaultVisual (d, 0), width, height); cairo_t * cairo = cairo_create (surface); cairo_select_font_face (cairo, "FreeSans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size (cairo, 40 ); cairo_set_source_rgb (cairo, 0.8, 0.8, 0.8); cairo_move_to (cairo, 40.0, 60.0); cairo_show_text (cairo, std::to_string (counter).c_str ()); XFlush (d); struct timeval next_update; struct timeval now; struct timeval interval = { 0, 500000 }; gettimeofday(&now, NULL); timeradd(&now, &interval, &next_update); while (true) { XEvent event; gettimeofday(&now, NULL); if (timercmp(&now, &next_update, >)) { // Store time of next update timeradd(&now, &interval, &next_update); puts("update"); do_update(); } if (!XPending(d)) { struct timeval remaining; fd_set fds; int fd = ConnectionNumber(d); FD_ZERO(&fds); FD_SET(fd, &fds); timersub(&next_update, &now, &remaining); select(fd + 1, &fds, NULL, NULL, &remaining); } else { XNextEvent (d, & event); if (event.type == Expose) { XClearWindow (d, w); cairo_move_to (cairo, 40.0, 60.0); cairo_show_text (cairo, std::to_string (counter).c_str ()); } if (event.type == ConfigureNotify) { cairo_xlib_surface_set_size (surface, event.xconfigure.width, event.xconfigure.height); } else if (event.type == KeyPress) { XCloseDisplay (d); return 0; } } } }
creat colored cube consisting triangles in android studio
I only managed to fix a triangle. This is the code but do not know what to do to get it as a cube. I tried to fix the code but did not get the cube, so this code is before I destroyed it. Will try to get it to rotate too. public class Triangle { static final int VERTEX_POS_SIZE = 4; static final int COLOR_SIZE = 4; static final int VERTEX_POS_INDEX = 0; static final int COLOR_INDEX = 1; static final int VERTEX_POS_OFFSET = 0; static final int COLOR_OFFSET = 0; static final int VERTEX_ATTRIB_SIZE = VERTEX_POS_SIZE; static final int COLOR_ATTRIB_SIZE = COLOR_SIZE; private final int VERTEX_COUNT = triangleData.length / VERTEX_ATTRIB_SIZE; private FloatBuffer vertexDataBuffer; private FloatBuffer colorDataBuffer; static float triangleData[] = { // in counterclockwise order: 0.0f, 0.0f, 0.0f, 1.0f, // top 1.0f, 0.0f, 0.0f, 1.0f, // bottom left 1.0f, 0.0f, -1.0f, 1.0f, // bottom right 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f, }; static float colorData[] = { // in counterclockwise order: 1.0f, 0.0f, 0.0f, 1.0f, // Red 0.0f, 1.0f, 0.0f, 1.0f, // Green 0.0f, 0.0f, 1.0f, 1.0f// Blue }; // Set color with red, green, blue and alpha (opacity) values float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f }; private final int mProgram; private final String vertexShaderCode = // This matrix member variable provides a hook to manipulate // the coordinates of the objects that use this vertex shader "attribute vec4 vPosition; \n" + "attribute vec4 vColor; \n" + "uniform mat4 uMVPMatrix;\n" + "varying vec4 c; \n" + "void main() { \n" + " c = vColor; \n" + // the matrix must be included as a modifier of gl_Position // Note that the uMVPMatrix factor *must be first* in order // for the matrix multiplication product to be correct. " gl_Position = uMVPMatrix * vPosition;\n" + "}"; private final String fragmentShaderCode = "precision mediump float;\n" + "varying vec4 c;\n" + "void main() {\n" + " gl_FragColor = c;\n" + "}"; // Use to access and set the view transformation private int mMVPMatrixHandle; private int positionHandle; private int colorHandle; public Triangle() { // initialize vertex byte buffer for shape coordinates ByteBuffer bbv = ByteBuffer.allocateDirect( // (number of coordinate values * 4 bytes per float) triangleData.length * 4); // use the device hardware's native byte order bbv.order(ByteOrder.nativeOrder()); // create a floating point buffer from the ByteBuffer vertexDataBuffer = bbv.asFloatBuffer(); // add the coordinates to the FloatBuffer vertexDataBuffer.put(triangleData); // set the buffer to read the first coordinate vertexDataBuffer.position(0); // initialize vertex byte buffer for shape coordinates ByteBuffer bbc = ByteBuffer.allocateDirect( // (number of coordinate values * 4 bytes per float) colorData.length * 4); // use the device hardware's native byte order bbc.order(ByteOrder.nativeOrder()); // create a floating point buffer from the ByteBuffer colorDataBuffer = bbc.asFloatBuffer(); // add the coordinates to the FloatBuffer colorDataBuffer.put(colorData); // set the buffer to read the first coordinate colorDataBuffer.position(0); int vertexShader = CGRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); int fragmentShader = CGRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); // create empty OpenGL ES Program mProgram = GLES20.glCreateProgram(); // add the vertex shader to program GLES20.glAttachShader(mProgram, vertexShader); // add the fragment shader to program GLES20.glAttachShader(mProgram, fragmentShader); // creates OpenGL ES program executables GLES20.glLinkProgram(mProgram); } public void draw(float[] mvpMatrix) { // Add program to OpenGL ES environment GLES20.glUseProgram(mProgram); // get handle to shape's transformation matrix mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); positionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); GLES20.glEnableVertexAttribArray(positionHandle); // Prepare the triangle coordinate data GLES20.glVertexAttribPointer(positionHandle, VERTEX_POS_SIZE, GLES20.GL_FLOAT, false, VERTEX_ATTRIB_SIZE * 4, vertexDataBuffer); colorHandle = GLES20.glGetAttribLocation(mProgram, "vColor"); GLES20.glEnableVertexAttribArray(colorHandle); GLES20.glVertexAttribPointer(colorHandle, COLOR_SIZE, GLES20.GL_FLOAT, false, COLOR_ATTRIB_SIZE * 4, colorDataBuffer); // Pass the projection and view transformation to the shader GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0); // Draw the triangle GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, VERTEX_COUNT); // Disable vertex array GLES20.glDisableVertexAttribArray(positionHandle); GLES20.glDisableVertexAttribArray(colorHandle); } }
OpenGL double buffers on Ubuntu does not work
I'm testing out several of Sumantha Guha's code and there's something that isn't working quite right... All of the sample code where he uses GLUT_DOUBLE and glutSwapBuffers() does not work on my ubuntu machine, but works on my Windows machine. More accurately the window that pops out simply traces the background. I've had this issue before on Windows where Flush and single buffers don't work, but now this is happening on Linux where Double buffers and glutSwapBuffers do not work. Any idea as to what may be causing this? Sample of code that I tried loading. Compiles fine, just get a window that traces the background. /////////////////////////////////////////////////////////////////////////////////////////////////////// // loadTextures.cpp // // This stripped-down program shows how to load both external and program-generated images as textures. // // NOTE: The Textures folder must be in the same one as this program. // // Interaction: // Press the left and right arrow keys to rotate the square. // Press space to toggle between textures. // Press delete to reset. // // Sumanta Guha /////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////// // TEXTURE GREDITS: // canLabel.bmp, thanks anonymous. // canTop.bmp, thanks www.acoustica.com. // cray2.bmp, thanks NASA website www.nasa.gov. // grass.bmp, thanks www.amazingtextures.com. // launch.bmp, thanks NASA website www.nasa.gov. // nightsky.bmp, thanks anonymous. // sky.bmp, thanks www.mega-tex.nl. // trees.bmp, thanks anonymous. //////////////////////////////////////////////// #include <cstdlib> #include <iostream> #include <fstream> #ifdef __APPLE__ # include <GLUT/glut.h> # include <OpenGL/glext.h> #else # include <GL/glut.h> # include <GL/glext.h> #endif using namespace std; // Globals. static unsigned int texture[2]; // Array of texture indices. static unsigned char chessboard[64][64][3]; // Storage for chessboard image. static float angle = 0.0; // Angle to rotate textured square. static int id = 0; // Currently displayed texture id. // Struct of bitmap file. struct BitMapFile { int sizeX; int sizeY; unsigned char *data; }; // Routine to read a bitmap file. // Works only for uncompressed bmp files of 24-bit color. BitMapFile *getBMPData(string filename) { BitMapFile *bmp = new BitMapFile; unsigned int size, offset, headerSize; // Read input file name. ifstream infile(filename.c_str(), ios::binary); // Get the starting point of the image data. infile.seekg(10); infile.read((char *) &offset, 4); // Get the header size of the bitmap. infile.read((char *) &headerSize,4); // Get width and height values in the bitmap header. infile.seekg(18); infile.read( (char *) &bmp->sizeX, 4); infile.read( (char *) &bmp->sizeY, 4); // Allocate buffer for the image. size = bmp->sizeX * bmp->sizeY * 24; bmp->data = new unsigned char[size]; // Read bitmap data. infile.seekg(offset); infile.read((char *) bmp->data , size); // Reverse color from bgr to rgb. int temp; for (int i = 0; i < size; i += 3) { temp = bmp->data[i]; bmp->data[i] = bmp->data[i+2]; bmp->data[i+2] = temp; } return bmp; } // Load external textures. void loadExternalTextures() { // Local storage for bmp image data. BitMapFile *image[1]; // Load the texture. image[0] = getBMPData("Textures/launch.bmp"); // Activate texture index texture[0]. glBindTexture(GL_TEXTURE_2D, texture[0]); // Set texture parameters for wrapping. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture parameters for filtering. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Specify an image as the texture to be bound with the currently active texture index. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image[0]->sizeX, image[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image[0]->data); } // Routine to load a program-generated image as a texture. void loadProceduralTextures() { // Activate texture index texture[1]. glBindTexture(GL_TEXTURE_2D, texture[1]); // Set texture parameters for wrapping. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture parameters for filtering. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Specify an image as the texture to be bound with the currently active texture index. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, chessboard); } // Create 64 x 64 RGB image of a chessboard. void createChessboard(void) { int i, j; for (i = 0; i < 64; i++) for (j = 0; j < 64; j++) if ( ( ((i/8)%2) && ((j/8)%2) ) || ( !((i/8)%2) && !((j/8)%2) ) ) { chessboard[i][j][0] = 0x00; chessboard[i][j][1] = 0x00; chessboard[i][j][2] = 0x00; } else { chessboard[i][j][0] = 0xFF; chessboard[i][j][1] = 0xFF; chessboard[i][j][2] = 0xFF; } } // Initialization routine. void setup(void) { glClearColor(0.8, 0.8, 0.8, 0.0); // Create texture index array. glGenTextures(2, texture); // Load external texture and generate and load procedural texture. loadExternalTextures(); createChessboard(); loadProceduralTextures(); // Turn on OpenGL texturing. glEnable(GL_TEXTURE_2D); // Specify how texture values combine with current surface color values. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } // Drawing routine. void drawScene(void) { glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); gluLookAt(0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glRotatef(angle, 0.0, 1.0, 0.0); // Activate a texture. glBindTexture(GL_TEXTURE_2D, texture[id]); // Map the texture onto a square polygon. glBegin(GL_POLYGON); glTexCoord2f(0.0, 0.0); glVertex3f(-10.0, -10.0, 0.0); glTexCoord2f(1.0, 0.0); glVertex3f(10.0, -10.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex3f(10.0, 10.0, 0.0); glTexCoord2f(0.0, 1.0); glVertex3f(-10.0, 10.0, 0.0); glEnd(); glutSwapBuffers(); } // OpenGL window reshape routine. void resize(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-5.0, 5.0, -5.0, 5.0, 5.0, 100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } // Keyboard input processing routine. void keyInput(unsigned char key, int x, int y) { switch(key) { case 27: exit(0); break; case ' ': id++; if (id == 2) id = 0; glutPostRedisplay(); break; case 127: angle = 0.0; glutPostRedisplay(); break; default: break; } } // Callback routine for non-ASCII key entry. void specialKeyInput(int key, int x, int y) { if (key == GLUT_KEY_LEFT) { angle -= 5.0; if (angle < 0.0) angle += 360.0; } if (key == GLUT_KEY_RIGHT) { angle += 5.0; if (angle > 360.0) angle -= 360.0; } glutPostRedisplay(); } // Routine to output interaction instructions to the C++ window. void printInteraction(void) { cout << "Interaction:" << endl; cout << "Press the left and right arrow keys to rotate the square." << endl << "Press space to toggle between textures." << endl << "Press delete to reset." << endl; } // Main routine. int main(int argc, char **argv) { printInteraction(); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); glutCreateWindow("loadTextures.cpp"); setup(); glutDisplayFunc(drawScene); glutReshapeFunc(resize); glutKeyboardFunc(keyInput); glutSpecialFunc(specialKeyInput); glutMainLoop(); return 0; }
Loading Textures in Init()
Trying to texture a skybox and loading the textures fine with "ImageLoader::createJPG", which loads a texture file in the proper format and my code textures it to the polygons just fine if I load them in every display loop (which is obviously an awful performance hit.) But when I try the same code in init() just to load them once, display doesn't even think they exist (I just end up with a cube of the default colour.) GLuint skyFront; etc. is declared before anything else at the top of the file just after the #includes. No amount of enables or texParameters seems to make init() want to load the textures. Any ideas? GLuint skyTop; GLuint skyFront; GLuint skyBack; GLuint skyBottom; GLuint skyLeft; GLuint skyRight; void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0,0,-0.6); glTranslatef(0, -0.4, -1); glPushMatrix(); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glDisable(GL_BLEND); //glEnable(GL_LIGHT0); //glTranslatef(camPos.x, camPos.y,camPos.z); //glDepthMask(GL_FALSE); glDisable(GL_CULL_FACE); //draw skybox glLoadIdentity(); glEnable(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glColor3f(0.0, 1.0, 0.0); glTranslatef(0.0,-2.0,-20.0); GLuint skyTop = ImageLoader::createJPG("../TestModels/top.jpg"); GLuint skyBottom = ImageLoader::createJPG("../TestModels/bottom.jpg"); GLuint skyLeft = ImageLoader::createJPG("../TestModels/left.jpg"); GLuint skyFront = ImageLoader::createJPG("../TestModels/front.jpg"); GLuint skyRight = ImageLoader::createJPG("../TestModels/right.jpg"); GLuint skyBack = ImageLoader::createJPG("../TestModels/back.jpg"); //FRONT glBindTexture(GL_TEXTURE_2D, skyFront); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(-SKYBOXSIZE, SKYBOXSIZE, -SKYBOXSIZE); //A glTexCoord2f(0, 1); glVertex3f(-SKYBOXSIZE, -SKYBOXSIZE, -SKYBOXSIZE); //B glTexCoord2f(1, 1); glVertex3f(SKYBOXSIZE, -SKYBOXSIZE, -SKYBOXSIZE); //C glTexCoord2f(1, 0); glVertex3f(SKYBOXSIZE, SKYBOXSIZE, -SKYBOXSIZE); //D glEnd(); glBindTexture(GL_TEXTURE_2D, skyLeft); //LEFT glBegin(GL_QUADS); glTexCoord2f(1, 1); glVertex3f(SKYBOXSIZE, SKYBOXSIZE, -SKYBOXSIZE); //D glTexCoord2f(0, 1); glVertex3f(SKYBOXSIZE, -SKYBOXSIZE, -SKYBOXSIZE); //C glTexCoord2f(0, 0); glVertex3f(SKYBOXSIZE, -SKYBOXSIZE, SKYBOXSIZE); //E glTexCoord2f(1, 0); glVertex3f(SKYBOXSIZE, SKYBOXSIZE, SKYBOXSIZE); //F glEnd(); etc. etc. edit: init() code looks like this: void init() { glewInit() GLuint skyFront = ImageLoader::createJPG("../TestModels/front.jpg"); //load the texture, damnit glClearColor(0.0,0.0,0.0,0.0); glShadeModel(GL_SMOOTH); //light position and colour GLfloat light_position[] = { 0.0, 0.0, 20.0,0.0 }; GLfloat white_light[] = {0.8,0.8,0.8,0.0}; GLfloat diff_light[] = {1.0,1.0,1.0,0.0}; GLfloat spec_light[] = {1.0,1.0,1.0,0.0}; glLightfv(GL_LIGHT0, GL_AMBIENT, white_light); glLightfv(GL_LIGHT0, GL_DIFFUSE, diff_light); glLightfv(GL_LIGHT0, GL_SPECULAR, spec_light); glLightfv(GL_LIGHT0, GL_POSITION, light_position); //ambient light GLfloat ambient[] = {0.3,0.3,0.3}; glMaterialfv(GL_FRONT, GL_AMBIENT, ambient); //diffuse material component GLfloat diff[] = {0.6,0.6,0.6}; glMaterialfv(GL_FRONT, GL_DIFFUSE, diff); //specular material component GLfloat WhiteSpec[] = {1,1,1}; glMaterialfv(GL_FRONT, GL_SPECULAR, WhiteSpec); GLfloat shininess = 50; glMaterialf(GL_FRONT, GL_SHININESS, shininess); //ENABLE LIGHTING AND DEPTH TEST glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); cout << " loading model " << endl; if(objLoader.loadModel("../TestModels/hummer.obj", model))//returns true if the model is loaded, puts the model in the model parameter { cout << " model loaded " << endl; //if you want to translate the object to the origin of the screen, //first calculate the centre of the object, then move all the vertices //back so that the centre is on the origin. model.calcCentrePoint(); model.centreOnZero(); model.calcVertNormalsUsingOctree(); //the method will construct the octree if it hasn't already been created. //turn on VBO by setting useVBO to true in 3dmodel.cpp default constructor - only permitted on 8 series cards and higher if(!model.useImmediateMode || model.useVBO) { model.initDrawElements(); } if(model.useVBO) { model.initVBO(); model.deleteVertexFaceData(); } } else { cout << " model failed to load " << endl; } } And all the rest of the GL commands go through and even the model I load goes through fine. TexPerameters and so on are defined in ImageLoader, yeah..
These are global: GLuint skyTop; GLuint skyFront; GLuint skyBack; GLuint skyBottom; GLuint skyLeft; GLuint skyRight; But this sets a local: void init() { glewInit() GLuint skyFront = ImageLoader::createJPG("../TestModels/front.jpg"); //load the texture, damnit You need to not re-declare the skyFront variable, and use the global instead.
Looking for code samples for Direct3D tessellation
I am trying to learn how to use the Direct3D function D3DXTessellateRectPatch: msdn.microsoft.com/en-us/library/bb205471(v=VS.85).aspx I have found the MSDN documentation quite useful and have been able to implement tessellation of a single rectangle patch. I am now trying to tesselate a mesh that consists of thirty two bicubic Bezier 3D patches (the Utah teapot). I have tried a simple approach - tesselate each Bezier curve individually, then join the vertices and indices appropriately, taking into account vertex offsets, to create a tessellated merged mesh. However, this does not quite seem to have the desired result. If anyone has hints on this problem or, even better, code samples, much appreciated. Specifically, I have checked: Www.directxtutorial.com http://www.amazon.com/Introduction-Game-Programming-Direct-9-0c/dp/1598220160/ And another Direct3D reference, as well as Google. Thank you and look forward to your advice/pointers. Yours Misha
Tim C Schroeder has been a huge help and suggested I use ID3DXPatchMesh. Here is some sample code that generates a tessellated teapot (place in file tester.cpp): // Main D3DX framework from www.directxtutorial.com (free section) #include <assert.h> #include <stdio.h> // include the basic windows header files and the Direct3D header file #include <windows.h> #include <windowsx.h> #include <d3d9.h> #include <d3dx9.h> // define the screen resolution #define SCREEN_WIDTH 800 #define SCREEN_HEIGHT 600 // include the Direct3D Library files #pragma comment (lib, "d3d9.lib") #pragma comment (lib, "d3dx9.lib") // global declarations LPDIRECT3D9 d3d; LPDIRECT3DDEVICE9 d3ddev; LPD3DXMESH mesh = NULL; // define the mesh pointer // function prototypes void initD3D(HWND hWnd); void render_frame(void); void cleanD3D(void); void init_graphics(void); struct vertex_data { D3DXVECTOR3 position; DWORD color; }; #define FVF_VERTEX_DATA (D3DFVF_XYZ | D3DFVF_DIFFUSE) // the WindowProc function prototype LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); // the entry point for any Windows program int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HWND hWnd; WNDCLASSEX wc; ZeroMemory(&wc, sizeof(WNDCLASSEX)); wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpszClassName = "WindowClass"; RegisterClassEx(&wc); hWnd = CreateWindowEx(NULL, "WindowClass", "Our Direct3D Program", WS_OVERLAPPEDWINDOW, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL); ShowWindow(hWnd, nCmdShow); initD3D(hWnd); MSG msg; while(TRUE) { while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } if(msg.message == WM_QUIT) break; render_frame(); } cleanD3D(); return msg.wParam; } // this is the main message handler for the program LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc (hWnd, message, wParam, lParam); } // this function initializes and prepares Direct3D for use void initD3D(HWND hWnd) { d3d = Direct3DCreate9(D3D_SDK_VERSION); D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.hDeviceWindow = hWnd; d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; d3dpp.BackBufferWidth = SCREEN_WIDTH; d3dpp.BackBufferHeight = SCREEN_HEIGHT; d3dpp.EnableAutoDepthStencil = TRUE; d3dpp.AutoDepthStencilFormat = D3DFMT_D16; d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); init_graphics(); d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE); // turn off the 3D lighting d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); // turn off culling d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE); // turn on the z-buffer } // this is the function used to render a single frame void render_frame(void) { d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); d3ddev->BeginScene(); d3ddev->SetFVF(FVF_VERTEX_DATA); // set the view transform D3DXMATRIX matView; // the view transform matrix D3DXMatrixLookAtLH(&matView, &D3DXVECTOR3 (0.0f, 8.0f, 25.0f), // the camera position &D3DXVECTOR3 (0.0f, 0.0f, 0.0f), // the look-at position &D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // the up direction d3ddev->SetTransform(D3DTS_VIEW, &matView); // set the view transform to matView // set the projection transform D3DXMATRIX matProjection; // the projection transform matrix D3DXMatrixPerspectiveFovLH(&matProjection, D3DXToRadian(45), // the horizontal field of view (FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, // aspect ratio 1.0f, // the near view-plane 100.0f); // the far view-plane d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection); // set the projection // set the world transform static float index = 0.0f; index+=0.03f; // an ever-increasing float value D3DXMATRIX matRotateY; // a matrix to store the rotation for each triangle D3DXMatrixRotationY(&matRotateY, index); // the rotation matrix d3ddev->SetTransform(D3DTS_WORLD, &(matRotateY)); // set the world transform if (mesh) mesh->DrawSubset(0); d3ddev->EndScene(); d3ddev->Present(NULL, NULL, NULL, NULL); } // this is the function that cleans up Direct3D and COM void cleanD3D(void) { if (mesh) mesh->Release(); d3ddev->Release(); d3d->Release(); } #define MAX_PATCHES 1000 #define POINTS_PER_PATCH 16 int num_patches = -1; int patches[MAX_PATCHES][POINTS_PER_PATCH]; void B_patch(int ii, int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m, int n, int o, int p) { assert(ii < MAX_PATCHES); patches[ii][0] = a-1; patches[ii][1] = b-1; patches[ii][2] = c-1; patches[ii][3] = d-1; patches[ii][4] = e-1; patches[ii][5] = f-1; patches[ii][6] = g-1; patches[ii][7] = h-1; patches[ii][8] = i-1; patches[ii][9] = j-1; patches[ii][10] = k-1; patches[ii][11] = l-1; patches[ii][12] = m-1; patches[ii][13] = n-1; patches[ii][14] = o-1; patches[ii][15] = p-1; assert(POINTS_PER_PATCH==16); } #define MAX_POINTS 1000 int num_points = -1; D3DXVECTOR3 points[MAX_POINTS]; void B_point(int ii, double x, double y, double z) { ii--; assert(ii < MAX_POINTS); points[ii].x = x; /*** Y AND Z FLIPPED ***/ points[ii].y = z; points[ii].z = y; } // BEGIN http://www.sjbaker.org/teapot/teaset.tgz /* * The file input.c -- Juhana Kouhia, jk87377#cs.tut.fi, Oct. 25, 1991 * * Load_patch(filename, patches, vertices); * char *filename; int *patches, *vertices; * A sample program to read Bezier patches in. * Returns count of patches and vertices. * User defined subroutines: * B_patch(ii, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p); * int ii, a, b, ..., p; * Defines one Bezier patch with index number ii, * indexes to points are in a, b, c, ..., p. * B_point(ii, x, y, z); * int ii; double x, y, z; * Defines one point with index number ii. */ #include <stdio.h> // Modified to work with g++ void Load_patch(char *filename, int *patches, int *vertices) { int ii; float x,y,z; int a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p; FILE *fp; if (!(fp = fopen(filename,"r"))) { fprintf(stderr,"Load_patch: Can't open %s\n",filename); exit(1); } (void)fscanf(fp,"%i\n",patches); for (ii = 0; ii < *patches; ii++) { (void)fscanf(fp,"%i, %i, %i, %i,",&a,&b,&c,&d); (void)fscanf(fp,"%i, %i, %i, %i,",&e,&f,&g,&h); (void)fscanf(fp,"%i, %i, %i, %i,",&i,&j,&k,&l); (void)fscanf(fp,"%i, %i, %i, %i\n",&m,&n,&o,&p); B_patch(ii, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p); } (void)fscanf(fp,"%i\n",vertices); for (ii = 1; ii <= *vertices; ii++) { (void)fscanf(fp,"%f, %f, %f\n",&x,&y,&z); B_point(ii, (double)x,(double)y,(double)z); } } // END http://www.sjbaker.org/teapot/teaset.tgz // this is the function that puts the 3D models into video RAM void init_graphics(void) { // load patch char filename[255]; sprintf(filename,"teapot"); Load_patch(filename,&num_patches,&num_points); printf("Loaded patch %s with %d patches and %d vertices.\n", filename,num_patches,num_points); // create declarator from FVF D3DVERTEXELEMENT9 inDecl[MAX_FVF_DECL_SIZE]; if (!SUCCEEDED(D3DXDeclaratorFromFVF(FVF_VERTEX_DATA,inDecl))) assert(FALSE); // create patch mesh LPD3DXPATCHMESH p_mesh; D3DXPATCHINFO info; info.PatchType = D3DXPATCHMESH_RECT; info.Degree = D3DDEGREE_CUBIC; info.Basis = D3DBASIS_BEZIER; if (!SUCCEEDED(D3DXCreatePatchMesh(&info,num_patches,num_points,0,inDecl,d3ddev,&p_mesh))) assert(FALSE); assert(p_mesh->GetControlVerticesPerPatch()==POINTS_PER_PATCH); // copy vertices LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL; if (!SUCCEEDED(p_mesh->GetVertexBuffer(&v_buffer))) assert(FALSE); struct vertex_data* vertex_data = NULL; DWORD number_of_vertices=p_mesh->GetNumVertices(); assert(number_of_vertices==num_points); if (!SUCCEEDED(v_buffer->Lock(0,number_of_vertices*sizeof(struct vertex_data),(void **)&vertex_data,D3DLOCK_DISCARD))) assert(FALSE); for (int i=0; i<num_points; i++) { vertex_data[i].position.x = points[i].x; vertex_data[i].position.y = points[i].y; vertex_data[i].position.z = points[i].z; vertex_data[i].color = D3DCOLOR_XRGB(255,0,0); } v_buffer->Unlock(); v_buffer->Release(); // copy indices LPDIRECT3DINDEXBUFFER9 i_buffer = NULL; if (!SUCCEEDED(p_mesh->GetIndexBuffer(&i_buffer))) assert(FALSE); D3DINDEXBUFFER_DESC i_buffer_desc; if (!SUCCEEDED(i_buffer->GetDesc(&i_buffer_desc))) assert(FALSE); assert(i_buffer_desc.Size==num_patches*POINTS_PER_PATCH*sizeof(WORD)); WORD* index_data = NULL; if (!SUCCEEDED(i_buffer->Lock(0,0,(void **)&index_data,D3DLOCK_DISCARD))) assert(FALSE); int idx=0; for (int i=0; i<num_patches; i++) { for (int j=0; j<POINTS_PER_PATCH; j++) { index_data[idx] = patches[i][j]; idx++; } } i_buffer->Unlock(); i_buffer->Release(); // create mesh for tesselation FLOAT fTessLevel=1.0f; DWORD Adaptive=FALSE; DWORD NumTriangles,NumVertices; if (!SUCCEEDED(p_mesh->GetTessSize(fTessLevel,Adaptive,&NumTriangles,&NumVertices))) assert(FALSE); if (!SUCCEEDED(D3DXCreateMeshFVF(NumTriangles,NumVertices,D3DXMESH_MANAGED,FVF_VERTEX_DATA,d3ddev,&mesh))) assert(FALSE); // tesselate assert(Adaptive==FALSE); if (!SUCCEEDED(p_mesh->Tessellate(fTessLevel,mesh))) assert(FALSE); printf("Generated tesselated mesh with %d triangles, %d vertices\n",NumTriangles,NumVertices); p_mesh->Release(); } The teapot data (place in file teapot) is (from http://www.sjbaker.org/teapot/teaset.tgz): 32 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 4,17,18,19,8,20,21,22,12,23,24,25,16,26,27,28 19,29,30,31,22,32,33,34,25,35,36,37,28,38,39,40 31,41,42,1,34,43,44,5,37,45,46,9,40,47,48,13 13,14,15,16,49,50,51,52,53,54,55,56,57,58,59,60 16,26,27,28,52,61,62,63,56,64,65,66,60,67,68,69 28,38,39,40,63,70,71,72,66,73,74,75,69,76,77,78 40,47,48,13,72,79,80,49,75,81,82,53,78,83,84,57 57,58,59,60,85,86,87,88,89,90,91,92,93,94,95,96 60,67,68,69,88,97,98,99,92,100,101,102,96,103,104,105 69,76,77,78,99,106,107,108,102,109,110,111,105,112,113,114 78,83,84,57,108,115,116,85,111,117,118,89,114,119,120,93 121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136 124,137,138,121,128,139,140,125,132,141,142,129,136,143,144,133 133,134,135,136,145,146,147,148,149,150,151,152,69,153,154,155 136,143,144,133,148,156,157,145,152,158,159,149,155,160,161,69 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177 165,178,179,162,169,180,181,166,173,182,183,170,177,184,185,174 174,175,176,177,186,187,188,189,190,191,192,193,194,195,196,197 177,184,185,174,189,198,199,186,193,200,201,190,197,202,203,194 204,204,204,204,207,208,209,210,211,211,211,211,212,213,214,215 204,204,204,204,210,217,218,219,211,211,211,211,215,220,221,222 204,204,204,204,219,224,225,226,211,211,211,211,222,227,228,229 204,204,204,204,226,230,231,207,211,211,211,211,229,232,233,212 212,213,214,215,234,235,236,237,238,239,240,241,242,243,244,245 215,220,221,222,237,246,247,248,241,249,250,251,245,252,253,254 222,227,228,229,248,255,256,257,251,258,259,260,254,261,262,263 229,232,233,212,257,264,265,234,260,266,267,238,263,268,269,242 270,270,270,270,279,280,281,282,275,276,277,278,271,272,273,274 270,270,270,270,282,289,290,291,278,286,287,288,274,283,284,285 270,270,270,270,291,298,299,300,288,295,296,297,285,292,293,294 270,270,270,270,300,305,306,279,297,303,304,275,294,301,302,271 306 1.4,0.0,2.4 1.4,-0.784,2.4 0.784,-1.4,2.4 0.0,-1.4,2.4 1.3375,0.0,2.53125 1.3375,-0.749,2.53125 0.749,-1.3375,2.53125 0.0,-1.3375,2.53125 1.4375,0.0,2.53125 1.4375,-0.805,2.53125 0.805,-1.4375,2.53125 0.0,-1.4375,2.53125 1.5,0.0,2.4 1.5,-0.84,2.4 0.84,-1.5,2.4 0.0,-1.5,2.4 -0.784,-1.4,2.4 -1.4,-0.784,2.4 -1.4,0.0,2.4 -0.749,-1.3375,2.53125 -1.3375,-0.749,2.53125 -1.3375,0.0,2.53125 -0.805,-1.4375,2.53125 -1.4375,-0.805,2.53125 -1.4375,0.0,2.53125 -0.84,-1.5,2.4 -1.5,-0.84,2.4 -1.5,0.0,2.4 -1.4,0.784,2.4 -0.784,1.4,2.4 0.0,1.4,2.4 -1.3375,0.749,2.53125 -0.749,1.3375,2.53125 0.0,1.3375,2.53125 -1.4375,0.805,2.53125 -0.805,1.4375,2.53125 0.0,1.4375,2.53125 -1.5,0.84,2.4 -0.84,1.5,2.4 0.0,1.5,2.4 0.784,1.4,2.4 1.4,0.784,2.4 0.749,1.3375,2.53125 1.3375,0.749,2.53125 0.805,1.4375,2.53125 1.4375,0.805,2.53125 0.84,1.5,2.4 1.5,0.84,2.4 1.75,0.0,1.875 1.75,-0.98,1.875 0.98,-1.75,1.875 0.0,-1.75,1.875 2.0,0.0,1.35 2.0,-1.12,1.35 1.12,-2.0,1.35 0.0,-2.0,1.35 2.0,0.0,0.9 2.0,-1.12,0.9 1.12,-2.0,0.9 0.0,-2.0,0.9 -0.98,-1.75,1.875 -1.75,-0.98,1.875 -1.75,0.0,1.875 -1.12,-2.0,1.35 -2.0,-1.12,1.35 -2.0,0.0,1.35 -1.12,-2.0,0.9 -2.0,-1.12,0.9 -2.0,0.0,0.9 -1.75,0.98,1.875 -0.98,1.75,1.875 0.0,1.75,1.875 -2.0,1.12,1.35 -1.12,2.0,1.35 0.0,2.0,1.35 -2.0,1.12,0.9 -1.12,2.0,0.9 0.0,2.0,0.9 0.98,1.75,1.875 1.75,0.98,1.875 1.12,2.0,1.35 2.0,1.12,1.35 1.12,2.0,0.9 2.0,1.12,0.9 2.0,0.0,0.45 2.0,-1.12,0.45 1.12,-2.0,0.45 0.0,-2.0,0.45 1.5,0.0,0.225 1.5,-0.84,0.225 0.84,-1.5,0.225 0.0,-1.5,0.225 1.5,0.0,0.15 1.5,-0.84,0.15 0.84,-1.5,0.15 0.0,-1.5,0.15 -1.12,-2.0,0.45 -2.0,-1.12,0.45 -2.0,0.0,0.45 -0.84,-1.5,0.225 -1.5,-0.84,0.225 -1.5,0.0,0.225 -0.84,-1.5,0.15 -1.5,-0.84,0.15 -1.5,0.0,0.15 -2.0,1.12,0.45 -1.12,2.0,0.45 0.0,2.0,0.45 -1.5,0.84,0.225 -0.84,1.5,0.225 0.0,1.5,0.225 -1.5,0.84,0.15 -0.84,1.5,0.15 0.0,1.5,0.15 1.12,2.0,0.45 2.0,1.12,0.45 0.84,1.5,0.225 1.5,0.84,0.225 0.84,1.5,0.15 1.5,0.84,0.15 -1.6,0.0,2.025 -1.6,-0.3,2.025 -1.5,-0.3,2.25 -1.5,0.0,2.25 -2.3,0.0,2.025 -2.3,-0.3,2.025 -2.5,-0.3,2.25 -2.5,0.0,2.25 -2.7,0.0,2.025 -2.7,-0.3,2.025 -3.0,-0.3,2.25 -3.0,0.0,2.25 -2.7,0.0,1.8 -2.7,-0.3,1.8 -3.0,-0.3,1.8 -3.0,0.0,1.8 -1.5,0.3,2.25 -1.6,0.3,2.025 -2.5,0.3,2.25 -2.3,0.3,2.025 -3.0,0.3,2.25 -2.7,0.3,2.025 -3.0,0.3,1.8 -2.7,0.3,1.8 -2.7,0.0,1.575 -2.7,-0.3,1.575 -3.0,-0.3,1.35 -3.0,0.0,1.35 -2.5,0.0,1.125 -2.5,-0.3,1.125 -2.65,-0.3,0.9375 -2.65,0.0,0.9375 -2.0,-0.3,0.9 -1.9,-0.3,0.6 -1.9,0.0,0.6 -3.0,0.3,1.35 -2.7,0.3,1.575 -2.65,0.3,0.9375 -2.5,0.3,1.125 -1.9,0.3,0.6 -2.0,0.3,0.9 1.7,0.0,1.425 1.7,-0.66,1.425 1.7,-0.66,0.6 1.7,0.0,0.6 2.6,0.0,1.425 2.6,-0.66,1.425 3.1,-0.66,0.825 3.1,0.0,0.825 2.3,0.0,2.1 2.3,-0.25,2.1 2.4,-0.25,2.025 2.4,0.0,2.025 2.7,0.0,2.4 2.7,-0.25,2.4 3.3,-0.25,2.4 3.3,0.0,2.4 1.7,0.66,0.6 1.7,0.66,1.425 3.1,0.66,0.825 2.6,0.66,1.425 2.4,0.25,2.025 2.3,0.25,2.1 3.3,0.25,2.4 2.7,0.25,2.4 2.8,0.0,2.475 2.8,-0.25,2.475 3.525,-0.25,2.49375 3.525,0.0,2.49375 2.9,0.0,2.475 2.9,-0.15,2.475 3.45,-0.15,2.5125 3.45,0.0,2.5125 2.8,0.0,2.4 2.8,-0.15,2.4 3.2,-0.15,2.4 3.2,0.0,2.4 3.525,0.25,2.49375 2.8,0.25,2.475 3.45,0.15,2.5125 2.9,0.15,2.475 3.2,0.15,2.4 2.8,0.15,2.4 0.0,0.0,3.15 0.0,-0.002,3.15 0.002,0.0,3.15 0.8,0.0,3.15 0.8,-0.45,3.15 0.45,-0.8,3.15 0.0,-0.8,3.15 0.0,0.0,2.85 0.2,0.0,2.7 0.2,-0.112,2.7 0.112,-0.2,2.7 0.0,-0.2,2.7 -0.002,0.0,3.15 -0.45,-0.8,3.15 -0.8,-0.45,3.15 -0.8,0.0,3.15 -0.112,-0.2,2.7 -0.2,-0.112,2.7 -0.2,0.0,2.7 0.0,0.002,3.15 -0.8,0.45,3.15 -0.45,0.8,3.15 0.0,0.8,3.15 -0.2,0.112,2.7 -0.112,0.2,2.7 0.0,0.2,2.7 0.45,0.8,3.15 0.8,0.45,3.15 0.112,0.2,2.7 0.2,0.112,2.7 0.4,0.0,2.55 0.4,-0.224,2.55 0.224,-0.4,2.55 0.0,-0.4,2.55 1.3,0.0,2.55 1.3,-0.728,2.55 0.728,-1.3,2.55 0.0,-1.3,2.55 1.3,0.0,2.4 1.3,-0.728,2.4 0.728,-1.3,2.4 0.0,-1.3,2.4 -0.224,-0.4,2.55 -0.4,-0.224,2.55 -0.4,0.0,2.55 -0.728,-1.3,2.55 -1.3,-0.728,2.55 -1.3,0.0,2.55 -0.728,-1.3,2.4 -1.3,-0.728,2.4 -1.3,0.0,2.4 -0.4,0.224,2.55 -0.224,0.4,2.55 0.0,0.4,2.55 -1.3,0.728,2.55 -0.728,1.3,2.55 0.0,1.3,2.55 -1.3,0.728,2.4 -0.728,1.3,2.4 0.0,1.3,2.4 0.224,0.4,2.55 0.4,0.224,2.55 0.728,1.3,2.55 1.3,0.728,2.55 0.728,1.3,2.4 1.3,0.728,2.4 0.0,0.0,0.0 1.5,0.0,0.15 1.5,0.84,0.15 0.84,1.5,0.15 0.0,1.5,0.15 1.5,0.0,0.075 1.5,0.84,0.075 0.84,1.5,0.075 0.0,1.5,0.075 1.425,0.0,0.0 1.425,0.798,0.0 0.798,1.425,0.0 0.0,1.425,0.0 -0.84,1.5,0.15 -1.5,0.84,0.15 -1.5,0.0,0.15 -0.84,1.5,0.075 -1.5,0.84,0.075 -1.5,0.0,0.075 -0.798,1.425,0.0 -1.425,0.798,0.0 -1.425,0.0,0.0 -1.5,-0.84,0.15 -0.84,-1.5,0.15 0.0,-1.5,0.15 -1.5,-0.84,0.075 -0.84,-1.5,0.075 0.0,-1.5,0.075 -1.425,-0.798,0.0 -0.798,-1.425,0.0 0.0,-1.425,0.0 0.84,-1.5,0.15 1.5,-0.84,0.15 0.84,-1.5,0.075 1.5,-0.84,0.075 0.798,-1.425,0.0 1.425,-0.798,0.0 Finally, to compile using mingw on Ubuntu 10.04 amd64 with proper software installed: #!/bin/bash rm tester.exe > /dev/null 2>&1 i586-mingw32msvc-g++ tester.cpp -o tester.exe -fcheck-new -Idxsdk/DXSDK/Include -ld3d9 dxsdk/DXSDK/Lib/x86/d3dx9.lib