Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
OpenGL Prototype - template for good code design, less overwhelming, less headache for maintenance
#include <iostream>
#include <gl/glut.h>
using namespace std;
int W = 500; // window width
int H = 500; // window height
float time = 0; // เวลาปลอมๆสำหรับทำอนิเมชัน
float timeRate = 0.001; // timeRate นี่เป็นเรทเวลาจำลอง ปรับได้ถ้าอยากให้อนิเมชันมันช้าหรือเร็วขึ้น
// your global variables here ...
// e.g. float x = 10;
float x = 10; // ลบได้
float angleA = 0; // ลบได้
float armAngle = 0; // ลบได้
// หน้าที่ของฟังก์ชันนี้คือวาด A อย่างเดียว "อย่าใช้มันเคลื่อนที่ทำอนิเมชัน"
// ที่สำคัญคือ ควรให้เป็นการวาดที่จุด (0, 0) อยู่ตรงกลาง เพราะเวลา transform มันจะได้ง่ายๆ
void drawA() {
glPushMatrix(); // จงมี push, pop ครอบในฟังก์ชันเสมอ เพื่อป้องกันไม่ให้มันส่ง effect กับรูปอื่นๆ
// ... transformation (translate, rotate, scale) ...
// draw your A (glBegin, glEnd)
glPopMatrix();
}
// drawB, drawC, drawD ...
void display() {
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// start drawing
glPushMatrix(); // เริ่มต้นวาดรูป แล้วใส่อนิเมชันด้วย
// transformation for animation
glTranslatef(x, 0, 0); // ตัวแปร x จะเปลี่ยนไปเรื่อยตามกาลเวลา ทำให้ drawA() ขยับ
// และสามารถวาดได้หลายอัน โดยการันตีได้ว่าจะไม่ transform ส่งผลต่อกัน
// เพราะข้างในฟังก์ชัน drawA() มี push, pop ครอบอยู่
drawA();
glTranslatef(20, 0, 0); // อย่างงี้จะได้ตัว A สองตัวที่วิ่งไปทางขวาเหมือนกัน อยู่ห่างกัน 20
glRotate(angleA, 0, 0, 1); // แถมตัวที่สองจะหมุน และจะไม่ส่งผลต่อรูปที่อยู่ข่างล่างๆ
drawA();
// หรือแม้กระทั่งใช้ for loop เพื่อวาด A สิบตัว
for (int i = 0; i < 10; i++) {
glTranslatef(20, 0, 0);
drawA();
}
glPopMatrix();
// end of drawing
// draw something else ...
// push, draw, pop ... do it like this forever...
glutSwapBuffers(); // ทำให้ภาพไม่กระพริบ
}
// ทำอนิเมชัน การเคลื่อนไหว ในนี้ โดยการปรับค่าตัวแปร global ต่างๆ ที่นิยามไว้ข้างบน
void idleFunc() {
// เช่น x += 0.01; เพื่อทำให้รูป A มันขยับทุกๆเฟรม ไปทีละ 0.01 หน่วย
x += 0.01 * timeRate; // ถ้าเป็นไปได้ให้คูณกับเวลาจำลอง timeRate แบบนี้ เพื่อเวลาเราแก้ timeRate ความเร็วมันจะได้เปลี่ยนกันทั้งจอ
// ฟังก์ชัน idleFunc() นี้จะถูกเรียกซ้ำๆ ถี่ๆยิบ เป็นพันครั้งต่อวินาที หรือตกต่ำได้ถึง 50 ครั้งต่อวินาที แล้วแต่ความเร็วคอมพิวเตอร์
// ดังนั้นถ้าคอมเร็วต้องปรับค่า x += เลขน้อยๆ
// ฟังก์ชันทำ animation ที่แนะนำคือ sin, cos เพราะมันจะสวยงามกว่าการเช็ค if, else อย่างเช่นเวลาต้องการให้
// แขนขยับไปมาอยู่ในช่วงมุม -90 ถึง 90 อย่างงี้ใช้ armAngle = sin(time) * 90; แทนเช็ค if-else แบบดิบๆ จะได้ความเป็นธรรมชาติมากกว่า
// แถมมันเขียนง่ายกว่า if-else ยาวๆอีก แล้วมันยังแสดงถึงความเป็นคณิตศาสตร์อีกด้วย
// (ฟังก์ชัน sine จะคืนค่าในช่วง -1 ถึง 1 มาให้ พอคูณ 90 มันเลยเป็น -90 ถึง 90)
armAngle = sinf(time * 0.5) * 90; // ใช้ sinf เพราะเป็น float
// เห็นตรง 0.5 หรือไม่ ตัวนี้เปลี่ยนได้ เป็นความถี่การเหวี่ยงแขน เช่นเดียวกับ 90 เป็นมุม
glutPostRedisplay(); // คำสั่งนี้จะเป็นการบอกคอมพิวเตอร์ว่า "เห้ย วาดรูปใหม่เดี๋ยวนี้เพราะข้าเปลี่ยนตัวแปร x แล้วนะ"
// โดยคอมพิวเตอร์มันจะไปเรียก display() อีกที ซึ่งแล้วแต่อารมณ์ความเร็วของมัน ว่ามันจะเรียกเมื่อไร
// แต่ส่วนใหญ่แล้วไม่ต้องกังวลเพราะใน 1 วิตาเรามองได้ทันแค่ 90 เฟรมต่อวิเท่านั้นแหละ
time += timeRate;
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(W, H);
gluOrtho2D(0, W, 0, H);
glutCreateWindow("Your Beautiful Window Name");
glutDisplayFunc(display);
glutIdleFunc(idleFunc);
glutMainLoop();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment