I'm trying to create an effect of zooming on a rotating hexagon. I'm accomplishing this by changing the window. Once it "zooms in" it supposed to "zoom out", and then repeat continuously. I've managed to zoom in just fine, and by the looks of my code, it should zoom out as well, but once it zooms in, nothing else is drawn. I've debugged my code, and i can tell that the variables are indeed being incremented on this line:
gluOrtho2D(cx - w, cx + w, cy -h, cy +h);
But yet i still fail to see my hexagon "zoom out". Any help would be appreciated. I'm pretty sure its something simple i'm forgetting. But it keeps eluding me. My code follows:
#include <cstdlib>
#include <GL/glut.h>
#include <cmath>
#define PI 3.14159265
#define ZOOM_IN 1
#define ZOOM_OUT -1
using namespace std;
const int screenWidth = 500;
const int screenHeight = 500;
float cx = 0.0, cy = 0.0; //center of viewport (cx, cy)
float h=1.2, w = 1.2; //window size
int NumFrames = 10; //frames
int frame = 0;
int direction = ZOOM_IN;
//<<<<<<<<<<<<<<<<<<<<<<< myInit >>>>>>>>>>>>>>>>>>>>
void myinit() {
glClearColor (1.0, 1.0, 1.0, 1.0); //set the background color to white
glColor3f (0.0, 0.0, 0.0); //set the foreground color to black
glPointSize (3.0); //set the point size to 3 X 3 pixels
glViewport (0.0, 0.0, 500.0, 500.0); //set the viewport to be the entire window
//set up a world window to screen transformation
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-5.0, 5.0, -5.0, 5.0);
// glMatrixMode (GL_MODELVIEW);
}
//<<<<<<<<<<<<<<<<<<<<<<< hexswirl >>>>>>>>>>>>>>>>>>>>
void hexswirl() {
double angle; //the angle of rotation
double angleInc = 2*PI/6.0; //the angle increment
double inc = 5.0/50; //the radius increment
double radius = 5.0/50.0; //the radius to be used
//clear the background
glClear (GL_COLOR_BUFFER_BIT);
//draw the hexagon swirl
for (int j = 0; j <= 50; j++) {
//the angle of rotation depends on which hexagon is
//being drawn.
angle = j* (PI/180.0);
//draw one hexagon
glBegin (GL_LINE_STRIP);
for (int k=0; k <= 6; k++) {
angle += angleInc;
glVertex2d(radius * cos(angle), radius *sin(angle));
}
glEnd();
//determine the radius of the next hexagon
radius += inc;
}
//swap buffers for a smooth change from one
//frame to another
glutSwapBuffers();
glutPostRedisplay();
glFlush();
}
//<<<<<<<<<<<<<<<<<<<<<<< viewZoom >>>>>>>>>>>>>>>>>>>>
void viewZoom(int i) {
if(direction == ZOOM_IN) {
//change the width and height of the window each time
w *= 0.9;
h *= 0.9;
}
if(direction == ZOOM_OUT) {
w /= 0.9;
h /= 0.9;
}
if(i%10 == 0) {
direction = -direction;
}
//change the window and draw the hexagon swirl
gluOrtho2D (cx - w, cx + w, cy - h, cy + h);
hexswirl();
glutPostRedisplay();
glutTimerFunc(200, viewZoom,i+1);
}
//<<<<<<<<<<<<<<<<<<<<<<<< main >>>>>>>>>>>>>>>>>>>>>>
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(screenWidth, screenHeight);
glutInitWindowPosition(100,100);
glutCreateWindow("hexanim");
glutDisplayFunc(hexswirl);
viewZoom(1);
myinit();
glutMainLoop();
return 1;
}
I figured out a way around my problem. I still don't know why my window wasn't redrawing after "zooming in", but i decided to implement it through changing my viewport instead. I ended up switching out:
gluOrtho2D (cx - w, cx + w, cy - h, cy + h);
for
cx = screenWidth / w;
cy = screenHeight / h;
glViewport((screenWidth-cx)/2, (screenHeight-cy)/2, cx, cy);
(and made all the corresponding changes associated with it).
Related
I tried to scroll text horizontally in a OpenGL app. The text comes perfect and smooth part by part at the screen when starting from the right side. When the first letter then touches the side of the window at the left side, the whole text disappears. I want that the text goes over the border, so that it vanished smoothly and start again from the right side. It's a sort of banner i try to make. Someone who knows how to solve this problem?
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
#ifdef WIN32
#include <windows.h>
#endif
#include <GL/gl.h>
#include <GL/glut.h>
using namespace std;
//static int font_index = 0;
int state = 1;
float xsize = 800;
float ysize = 300;
void print_bitmap_string(/*void* font,*/ const char* s)
{
while (*s) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *s);
s++;
}
}
void reshape(int w, int h)
{
GLdouble size;
GLdouble aspect;
/* Use the whole window. */
glViewport(0, 0, w, h);
/* We are going to do some 2-D orthographic drawing. */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
size = (GLdouble)((w >= h) ? w : h) / 2.0;
if (w <= h) {
aspect = (GLdouble)h / (GLdouble)w;
glOrtho(-size, size, -size * aspect, size * aspect, -100000.0, 100000.0);
}
else {
aspect = (GLdouble)w / (GLdouble)h;
glOrtho(-size * aspect, size * aspect, -size, size, -100000.0, 100000.0);
}
/* Make the world and window coordinates coincide so that 1.0 in */
/* model space equals one pixel in window space. */
glScaled(aspect, aspect, 1.0);
/* Now determine where to draw things. */
//glMatrixMode(GL_MODELVIEW);
//glLoadIdentity();
}
float yild;
float ystep;
float x_pos = xsize/2;
float y_pos = 70;
void draw()
{
const char* bitmap_font_names[7] = { "Testing train application for windows!!##" };
glPushMatrix();
/* Draw the strings, according to the current mode and font. */
glTranslatef(0.5, -100, 0);
//set the text color
glColor4f(0.0f, 173.0f, 115.0f, 1.0f);
//ystep = 100.0;
//yild = 20.0;
glRasterPos2f(x_pos, y_pos /* + 1.25 * yild*/);
print_bitmap_string(bitmap_font_names[0]);
glPopMatrix();
}
void display(void)
{
//change background color
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
draw();
glColor3f(0.0, 255.0, 0.0);
/*glBegin(GL_TRIANGLES);
glVertex2f(20 + x_pos, 0 + y_pos);
glVertex2f(50 + x_pos, 10 + y_pos);
glVertex2f(20 + x_pos, 20 + y_pos);
glEnd();*/
glutSwapBuffers();
}
void timer(int) {
glutPostRedisplay();
glutTimerFunc(1000 / 90, timer, 0);
switch (state) {
case 1:
if (x_pos > (-xsize / 2) - 200) {
x_pos -= 1;
}
else {
state = -1;
}
break;
case -1:
x_pos = (xsize / 2);
state = 1;
break;
}
cout << x_pos << endl;
}
int main(int argc, char** argv)
{
glutInitWindowSize(xsize, ysize);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutCreateWindow("Train Display");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutTimerFunc(1000, timer, 0);
glutMainLoop();
return 0;
}
It looks like OpenGL may not allow you to explicitly draw bitmaps outside of the viewport.
From the documentation on glRasterPos,
To set a valid raster position outside the viewport, first set a valid raster position, then call glBitmap with NULL as the bitmap parameter.
The documentation on glBitmap elaborates on this aspect:
To set a valid raster position outside the viewport, first set a valid raster position inside the viewport, then call glBitmap with NULL as the bitmap parameter and with xmove and ymove set to the offsets of the new raster position. This technique is useful when panning an image around the viewport.
I created Lines and when I'm rotate the line. Line will be stretch. How can I stop stretch at rotation time. When I change height in Ortho it will be not displaying properly. When Line is going left or right it will be start strtching but when it will be reach in main point it will come in real position.
#include<fstream>
#include<iostream>
#include<stdlib.h>
#include<glut.h>
using namespace std;
float yr = 0;
void introscreen();
void screen();
void screen1();
void PitchLadder();
int width = 1268;
int height = 720;
float translate = 0.0f;
GLfloat angle = 0.0f;
void display(void) {
glClearColor(0, 0, 0, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-300, 300, -10, 25, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
static int center_x = 0;
static int center_y = 0;
}
void specialKey(int key, int x, int y) {
switch (key) {
case GLUT_KEY_UP:
translate += 1.0f;
break;
case GLUT_KEY_DOWN:
translate -= 1.0f;
break;
case GLUT_KEY_LEFT:
angle += 1.0f;
break;
case GLUT_KEY_RIGHT:
angle -= 1.0f;
break;
}
glutPostRedisplay();
}
void Rolling(void) {
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0, 1, 0);
glPushMatrix();
glRotatef(-angle, 0, 0, 1);
glTranslatef(-10, translate,0);
PitchLadder();
glPopMatrix();
glFlush();
}
void PitchLadder() {
GLfloat y;
GLfloat y2;
GLfloat fSize[5];
GLfloat fCurrSize;
fCurrSize = fSize[2];
for (y2 = -90.0f ; y2 <= 90.0f ; y2 += 10.0f) {
glLineWidth(fCurrSize);
glBegin(GL_LINES);
glVertex3f(-50.0f , y2 , 0);
glVertex3f(50.0f , y2 , 0);
glEnd();
fCurrSize += 1.0f;
screen();
screen1();
}
}
void renderbitmap1(float x3, float y3, void *font1, char *string1) {
char *c1;
glRasterPos2f(x3, y3);
for (c1=string1; *c1 != '\0'; c1++) {
glutBitmapCharacter(font1, *c1);
}
}
void screen(void) {
glColor3f(0, 1, 0);
char buf1[20] = { '\0' };
for (int row1 = -90.0f; row1 <= 90 + yr; row1 +=10.0f) {
sprintf_s(buf1,"%i", row1);
renderbitmap1(70 , (yr+row1), GLUT_BITMAP_TIMES_ROMAN_24, buf1);
}
}
void renderbitmap2(float x4, float y4, void *font2, char *string2) {
char *c1;
glRasterPos2f(x4, y4);
for (c1=string2; *c1 != '\0'; c1++) {
glutBitmapCharacter(font2, *c1);
}
}
void screen1(void) {
glColor3f(0, 1, 0);
char buf1[20] = { '\0' };
for (int row1 = -90.0f; row1 <= 90 + yr; row1 +=10.0f) {
sprintf_s(buf1,"%i", row1);
renderbitmap2(-70 , (yr+row1), GLUT_BITMAP_TIMES_ROMAN_24, buf1);
}
}
int main(int arg, char** argv) {
glutInit(&arg, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(width, height);
glutInitWindowPosition(50, 100);
glutCreateWindow("HUD Lines");
display();
glutDisplayFunc(Rolling);
glutSpecialFunc(specialKey);
glutMainLoop();
return 0;
}
At Orthographic Projection, the view space coordinates are linearly mapped to the clip space coordinates respectively normalized device coordinates. The normlaized device space is a cube with a minimum of (-1, -1, -1) and a maximum of (1, 1, 1).
Finally the coordinates in normalized device space are mapped to the rectangular viewport.
If the viewport is rectangular then the aspect ratio has to be considered, when the view space coordinates are transformed to clip space.
The mapping of the normalized device coordinates to the viewport distorted the geometry by the reciprocal aspect ration of the viewport. This distortion has to be compensated by the orthographic projection.
When the orthographic projection is set by glOrtho(left, right, bottom, top, near, far), then the cuboid volume is defined, which maps (left, bottom, near) to (-1, -1, -1) and (right, top, far) to (1, 1, 1).
It is not necessary that the x and y range of the orthographic projection is equal the view port rectangle, bit the ration (left-right)/(top-bottom)hast to be equal the ration of the viewport rectangle else the geometry will be distored.
double size = 200.0f;
double aspect = (double)width / (double)height;
glOrtho(-aspect*size/2.0, aspect*size/2.0, -size/2.0, size/2.0, -1.0, 1.0);
Your window size and orthographic "view" do not have the same aspect ratio:
// This creates a window that's 1268 x 720 (a wide rectangle)
int width = 1268;
int height = 720;
glutInitWindowSize(width, height);
// This creates a "view" that's 300 x 300 (a square)
glOrtho(-300, 300, -10, 25, 0, 1);
The "view" will be stretched to fill the viewport (window). You are seeing a 300 x 300 image being stretched to 1268x720, which definitely makes horizontal lines appear longer than vertical lines even though they're the same length in the code.
You should call glOrtho using the width and height variables of your window:
glOrtho(0, width, 0, height, 0, 1);
Notice that I have changed the arguments to (left = 0, right = width, bottom = 0, top = height, ...). This allows you to work with a screen coordinate space that is similar to 2D rendering but the bottom-left corner is (0,0) and the top-right is (width,height).
I have program in which the object (a triangle) follows the mouse as it moves around and rotates to the direction its moving. What do I have to do to make it so the object stays still, until I click it, drag it to a position and once I release the mouse, it starts to move to that position?
#include <GL/glut.h>
#include <math.h>
# define ANIMATION_STEP (1000/300)
# define PI 3.1415926535897932
struct Globals {
centre_x, centre_y, rotate;
float length;
float mouse_x, mouse_y, speed;
int animating;
} globals;
void init(void){
// Starting position of the triangle
globals.centre_x = 100;
globals.centre_y = 100;
globals.rotate = 0.0;
globals.mouse_x = 300.0;
globals.mouse_y = 300.0;
// Animation speed in pixels per second
globals.speed = 300.0;
// size of the triangle
globals.length = 27;
globals.animating = 1;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 1000.0, 0.0, 700.0);
}
void triangle(void){
glBegin(GL_POLYGON);
glVertex2f(0.5, 0.0);
glVertex2f(-0.5, -0.5);
glVertex2f(-0.5, 0.5);
glEnd();
}
void display(void){
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(globals.mouse_x, globals.mouse_y, 0.0);
glRotatef(globals.rotate, 0.0, 0.0, 1.0);
glScalef(globals.length, globals.length, 1.0);
triangle();
glFlush();
glutSwapBuffers();
}
float limit(float x, float min, float max){
if (x < min) {
x = min;
}
if (x > max) {
x = max;
}
return x;
}
void timer(int v){
// Computing elapsed time for smooth animation.
int time = glutGet(GLUT_ELAPSED_TIME);
float angle;
glutTimerFunc(ANIMATION_STEP, timer, time);
if (globals.animating) {
int delta_t = time - v;
float delta_x, delta_y, length, step_size;
// Compute vector from current location to mouse
delta_x = globals.mouse_x - globals.centre_x;
delta_y = globals.mouse_y - globals.centre_y;
// Compute length of the vector
length = sqrt (delta_x*delta_x + delta_y*delta_y);
// If the triangle is close to the mouse, then no motion is required.
step_size = globals.speed * delta_t / 1000.0;
if (length > step_size * 0.55) {
delta_x = delta_x / length;
delta_y = delta_y / length;
globals.centre_x += delta_x * step_size;
globals.centre_y += delta_y * step_size;
angle = atan2(delta_y, delta_x);
globals.rotate = angle * 180.0 / PI;
// Keep the triangle inside the world window.
globals.centre_x = limit(globals.centre_x, 0.0 + globals.length/2, 1000.0 - globals.length/2);
globals.centre_y = limit(globals.centre_y, 0.0 + globals.length/2, 700.0 - globals.length/2);
}
glutPostRedisplay();
}
}
void mousemotion(int x, int yc){
globals.mouse_x = x;
globals.mouse_y = 700 - yc;
glutPostRedisplay();
}
main(int argc, char** argv){
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(1000, 700);
glutInitWindowPosition(10, 10);
glutDisplayFunc(display);
glutTimerFunc(ANIMATION_STEP, timer, 0);
glutPassiveMotionFunc(mousemotion);
init();
glutMainLoop();
return 0;
}
I have investigated processMouse() where if state == GLUT_DOWN then it records the current position and mouse press cordinates, but the best ive been able to get is that it immediately teleports to the mouse click. Can someone please explain what I would need to do to click on it, drag, release, then move to position?
in opengl, how to change mouse...
You don't. Mouse does not exist in OpenGL. Maybe you should change the question to "How to process mouse events in windows/GLUT/SDL/whatever-framework?" for which there are dozens of duplicates.
I am making a 3d project in OpenGL which contain a ground (drawn as line loops). The issue I have is when the project starts only a single line is drawn as shown in the next image:
When I resize or maximize the window then the actual ground gets displayed like this:
Any idea how to resolve this issue? I'm a beginner in OpenGL programming.
Here is the code :
void drawHook(void);
void timer(int);
void drawFlorr();
float L = 100;
const int screenWidth = 1000; // width of screen window in pixels
const int screenHeight = 1000; // height of screen window in pixels
float ww = 800;
float wh = 800;
float f = 520, n = 10.0;
static GLdouble ort1[] = { -200, 200, -33, 140 };
static GLdouble viewer[] = { 525, 25, -180 };
static GLdouble objec[] = { 525.0, 25, -350 };
float x, y = 0.0, z, z1;
float xmax = screenWidth - 200.0;
float zmax = screenWidth - 200.0;
float xmin, zmin;
float step = 5.0;
float fov = 80;
void myInit(void)
{
glClearColor(0.0,0.0,0.0,0.0); // background color is white
glPointSize(2.0); // a 'dot' is 2 by 2 pixels
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, screenWidth, 0.0, screenHeight);//dino window
glViewport(0, 0, screenWidth, screenHeight);
}
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
gluLookAt(viewer[0], viewer[1], viewer[2], objec[0], objec[1], objec[2], 0, 1, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fov, 1.333, n, f);
glPointSize(2.0);
glMatrixMode(GL_MODELVIEW);
drawFlorr();
glutSwapBuffers();
}
int main(int argc, char** argv)
{
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); // set display mode
glutInitWindowSize(screenWidth, screenHeight); // set window size
glutInitWindowPosition(10, 10); // set window position on screen
glutCreateWindow("Dino Line Drawing"); // open the screen window
glutDisplayFunc(myDisplay); // register redraw function
myInit();
//glutTimerFunc(1,timer,1);
glutMainLoop(); // go into a perpetual loop
return 1;
}
void drawFlorr()
{
xmin = -100;
zmin = -100;
for (x = xmin; x < xmax; x += step)
{
for (z = zmin; z < zmax; z += step)
{
z1 = -z;
glBegin(GL_LINE_LOOP);
glVertex3f(x, y, z1);
glVertex3f(x, y, z1-step+1.0);
glVertex3f(x + step - 1.0, y, z1 - step + 1.0);
glVertex3f(x+step-1.0, y, z1);
glEnd();
}
}
}
Your code is broken in many ways:
Your myDisplay function uses whatever the current matrix mode is to set the view matrix on.
Initially, you leave the matrix mode as GL_PROJECTION in myInit()
These two together mean that for the first frame, you just use identity as MODELVIEW matrix, and just overwrite the projection matrix twice. After a resize, the frame ais drawn again, and your code does waht you probably intented to do.
However, there is more:
You do not have any resize handler, so your viewport will not change when you resize the window.
You are setting an ortho matrix initailly for the projection, although you are not planning to use it at all.
and, the most import point:
All of your code depends on deprecated functionality which is not even available in modern OpenGL at all. You should really not use this in 2016, but learn modern OpenGL instead (with "modern" meaning "only a decade old" here).
I am working on an nbody simulator and I want to display it with OpenGL. I want to always be looking at the centre of mass reference frame. I have the following code. I calculate the COM and I set the center coordinate in the gluLookAt function to be the center of mass. I then subtract the "zoom" from the z coordinate to get the eye position. By logic this should ensure that I am always looking at whatever value the center of mass is. The only issue is that I marked where the center of mass should be on the screen with a red dot and it is moving. Shouldn't it never move if I am always looking at it from the same relative position? Here is my code. Focus on the display function since I assume that is where the error will be. I had similar code working in another project and I can't really find any differences.
#include "Universe.cuh"
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "timer.hpp"
#include <GL/glut.h>
Universe u;
float* vbuf;
double angle = 0.0, zoom = 1000;
void display()
{
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
float3 c = u.getCenterOfMass();
gluLookAt(c.x, c.y, c.z - zoom, c.x, c.y, c.z, 0, 1, 0);
glScalef(0.1, 0.1, 0.1);
glRotated(angle, 1, 0, 0);
glColor4f(1, 1, 1, 0.25);
glBegin(GL_POINTS);
{
glColor3f(1.0, 0.0, 0.0);
glVertex3d(c.x, c.y, c.z);
}
glEnd();
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, (double)w / (double)h, 1.0, zoom * 1e9);
glMatrixMode(GL_MODELVIEW);
}
void copy_to_vbuf()
{
for(int i = 0; i < u.size(); i++)
{
vbuf[3 * i + 0] = u.getObjects()[i].p.x;
vbuf[3 * i + 1] = u.getObjects()[i].p.y;
vbuf[3 * i + 2] = u.getObjects()[i].p.z;
}
}
void keyboard(unsigned char c, int x, int y)
{
if(c == 'w')
angle += 1;
else if(c == 's')
angle -= 1;
else if(c == '=')
zoom /= 1.2;
else if(c == '-')
zoom *= 1.2;
glutPostRedisplay();
}
void idle()
{
u.timeStep();
copy_to_vbuf();
glutPostRedisplay();
}
int main(int argc, char** argv)
{
cudaSetDevice(0);
srand(time(0));
u.getConfiguration().max_velocity = 10;
u.getConfiguration().softening_factor = 0.01;
u.getConfiguration().threshold_angle = 35;
u.getConfiguration().time_step = 0.1;
const int N = 5;
vbuf = new float[3 * N];
for(int i = 0; i < N; i++)
{
Object o;
o.m = rand() % 100 + 1;
o.p.x = 500.0 * rand() / RAND_MAX - 250.0;
o.p.y = 500.0 * rand() / RAND_MAX - 250.0;
o.p.z = 500.0 * rand() / RAND_MAX - 250.0;
u.addObject(o);
}
copy_to_vbuf();
glutInit(&argc, argv);
glutInitDisplayMode(GL_DOUBLE);
glutInitWindowSize(1000, 1000);
glutCreateWindow("N-Body");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutIdleFunc(idle);
glutKeyboardFunc(keyboard);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPointSize(1.0);
glutMainLoop();
return 0;
}
Two points regarding:
glScalef(0.1, 0.1, 0.1);
glRotated(angle, 1, 0, 0);
Since your axis is not centered on the 'COM', when you apply rotation the COM point will not stay in place and logically would move around the screen.
AFIK the normal order is scale,rotate,translate for transformations. This will apply the rotation and then scale.
EDIT:
To expand on that: Currently you take an arbitrary point rotate it, scale it and then focus on the point where it used to be. If you want to rotate your model (e.g. point marking the 'COM') around itself, it needs to be centered at (0,0,0).