Colour Colour::hsvMod(glm::ivec3 _hsvDelta){ glm::ivec3 hsv = rgbToHsv(*this) + _hsvDelta; hsv.x = glm::mod((float)hsv.x, 360.f); hsv.y = glm::min(100, glm::max(0, hsv.y)); hsv.z = glm::min(100, glm::max(0, hsv.z)); return Colour(hsvToRgb(hsv)); }
//------------------------------------------------------------------- void MyColormap::init() { begin = 0; end = MY_COLORMAP_RES; bDrawVirtical = false; // horizontal type = 0; int r, g, b; float coef = 360.0/MY_COLORMAP_RES; for(int i=0; i<MY_COLORMAP_RES; i++) { // go through hue cycle from 0 to 359 // hsvToRgb( 360-i, 255, (int)(255*((i-lowerlimit)/360.0)), r, g, b ); hsvToRgb(r, g, b, int(i*coef), 255, 255); data[i][0] = r; data[i][1] = g; data[i][2] = b; data[i][3] = 255; } glGenTextures(1, &tid); glBindTexture(GL_TEXTURE_1D, tid); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, MY_COLORMAP_RES, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); }
void idToRgb(unsigned int id, unsigned char& r, unsigned char& g, unsigned char& b) { float h = fmod(static_cast<float>(id)*M_PI, 1.0); float s = 0.5 + fmod(static_cast<float>(id)*M_PI*2, 0.5); float v = (id == 0 ? 0.0 : 0.75 + fmod(static_cast<float>(id)*M_PI*3, 0.25)); hsvToRgb(h, s, v, r, g, b); }
ColorRGB *ProceduralTexture::generateCelluarTexture(int size, ColorHSV color, int hueRange){ if (size<2) size = 2; int cellX = w/size+2; int cellY = h/size+2; int pointsX[cellX][cellY]; int pointsY[cellX][cellY]; ColorRGB cellColor[cellX][cellY]; srand(seed); for (int i=0; i<cellX; i++) for (int j=0; j<cellY; j++){ pointsX[i][j] = i*size+rand()%((int)(size*0.7))+size*0.15-size; pointsY[i][j] = j*size+rand()%((int)(size*0.7))+size*0.15-size; } color.h -= (hueRange/2); for (int i=0; i<cellX; i++) for (int j=0; j<cellY; j++){ ColorHSV c = color; c.h += rand()%hueRange; cellColor[i][j] = hsvToRgb(c); } ColorRGB *img = new ColorRGB[n]; for (int i=0; i<n; i++){ int x = i%w; int y = i/w; int px = 0; int py = 0; int min = INT_MAX; int startX = x/size; int finishX = startX+3; for (; startX<finishX; startX++){ int startY = y/size; int finishY = startY+3; for (; startY<finishY; startY++){ if (startX<0 || startX>=cellX || startY<0 || startY>=cellY) continue; int d = distance(x, y, pointsX[startX][startY], pointsY[startX][startY]); if (d<min){ px = startX; py = startY; min = d; } } } img[i] = cellColor[px][py]; } return img; }
void CycleHue(int huePoints) { int hueGap; if ((lastHue - targetHue) > 0) hueGap = lastHue - targetHue; else hueGap = (lastHue - targetHue) * -1; if (hueGap > huePoints) { if (lastHue > targetHue) lastHue = lastHue - huePoints; else lastHue = lastHue + huePoints; } else { lastHue = targetHue; targetHue = initialHue; initialHue = lastHue; } //for the waveform to match the lights hsvToRgb(((float)lastHue / 65535.0f), 1.0f, 1.0f, rgb); }
void LEDRainbowEffect::TransientLEDMode::update(void) { if (!Kaleidoscope.has_leds) return; uint16_t now = millis(); if ((now - rainbow_last_update) < parent_->rainbow_update_delay) { return; } else { rainbow_last_update = now; } cRGB rainbow = hsvToRgb(rainbow_hue, rainbow_saturation, parent_->rainbow_value); rainbow_hue += rainbow_steps; if (rainbow_hue >= 255) { rainbow_hue -= 255; } ::LEDControl.set_all_leds_to(rainbow); }
void ColorT<T>::set( ColorModel cm, const vec3 &v ) { switch( cm ) { case CM_HSV: { Colorf rgb = hsvToRgb( v ); r = CHANTRAIT<T>::convert( rgb.r ); g = CHANTRAIT<T>::convert( rgb.g ); b = CHANTRAIT<T>::convert( rgb.b ); } break; case CM_RGB: r = CHANTRAIT<T>::convert( v.x ); g = CHANTRAIT<T>::convert( v.y ); b = CHANTRAIT<T>::convert( v.z ); break; default: throw; } }
void ColorAT<T>::set( ColorModel cm, const vec4 &v ) { a = v.w; switch( cm ) { case CM_HSV: { Colorf rgb = hsvToRgb( vec3( v ) ); r = CHANTRAIT<T>::convert( rgb.r ); g = CHANTRAIT<T>::convert( rgb.g ); b = CHANTRAIT<T>::convert( rgb.b ); } break; case CM_RGB: r = CHANTRAIT<T>::convert( v.r ); g = CHANTRAIT<T>::convert( v.g ); b = CHANTRAIT<T>::convert( v.b ); break; default: throw ImageIoExceptionIllegalColorModel(); } }
void Gradient::fillGradient(QRgb* buffer, int length, double* data) const { double* temp = data ? data : new double[length * 3]; double* t1 = temp; double* t2 = temp + length; double* t3 = temp + 2 * length; _spline[0].generateSpline(t1, length); _spline[1].generateSpline(t2, length); _spline[2].generateSpline(t3, length); if (_isHsv) { for (int i=0; i < length; i++) buffer[i] = hsvToRgb(t1[i], t2[i], t3[i]); } else { for (int i=0; i < length; i++) buffer[i] = qRgb((int)(t1[i] * 255.0), (int)(t2[i] * 255.0), (int)(t3[i] * 255.0)); } if (!data) delete[] temp; }
void LEDRainbowWaveEffect::TransientLEDMode::update(void) { if (!Kaleidoscope.has_leds) return; uint16_t now = millis(); if ((now - rainbow_last_update) < parent_->rainbow_update_delay) { return; } else { rainbow_last_update = now; } for (int8_t i = 0; i < LED_COUNT; i++) { uint16_t key_hue = rainbow_hue + 16 * (i / 4); if (key_hue >= 255) { key_hue -= 255; } cRGB rainbow = hsvToRgb(key_hue, rainbow_saturation, parent_->rainbow_value); ::LEDControl.setCrgbAt(i, rainbow); } rainbow_hue += rainbow_wave_steps; if (rainbow_hue >= 255) { rainbow_hue -= 255; } }
//sets the colour to the given hue void updateColor(float h) { //scale the saturation position by 2 and reflect around 1 //s=abs((s*2.0)-1.0); //scale the saturation position by 2 and reflect around 1 //v=abs((v*2.0)-1.0); float s = 1; float v = 1; float r=0; float g=0; float b=0; //find the rgb values hsvToRgb(&r, &g, &b, h, s, v); //set the duty cycle duty[RED]=r*255; duty[GREEN]=g*255; duty[BLUE]=b*255; }
QColor ColorOperations::intToRgb(unsigned char val) { QColor hsv; hsv.setRgbF(intToHue(val), 1.0, 1.0, 1.0); return hsvToRgb(hsv); }
/** * Funktion zum verteilten berechnen der 2D-Temperaturverteilung. * @param status_flag Zeiger auf Variable, die enthält ob der Thread beendet ist. (0 = Beendet) * @param value_img Liste für die Daten der Temperaturverteilung. * @param image Grafik für die Temperaturverteilung. * @param width Breite der Temperaturverteilungsgrafik. * @param height Höhe der Temperaturverteilungsgrafik. * @param startheight Starthöhe für diesen Thread in der Grafik. * @param delta_h Höhe des von diesem Thread zu berechnenden Streifens. * @param info Informationen über die Eigenschaften der zu berechnenden Ebene. * @param xvec X-Achse der Ebene. * @param yvec Y-Achse der Ebene. * @param v0 Mittelpunkt der Ebene. * @param bases Möglichst einfache Geometrien Geometrien der Materialien. * @param obj Das aktuelle Objekt. * @param sensor_data Die zu verwendenden Sensordaten. * @param use_last_tet Versuchen, die Interpolation durch vorgezogenes Testen des zuletzt verwendeten Tetraeders zu beschleunigen. * Diese Option ist verursacht Ungenauigkeiten und bietet zumeist wenig Performancegewinn. */ void render_thread(bool* status_flag, float* value_img, wxImage* image, int width, int height, int startheight, int delta_h, CutRender_info* info, Vector3D* xvec, Vector3D* yvec, Vector3D* v0, vector<tetgenio*>* bases, ObjectData* obj, vector<SensorPoint>* sensor_data, bool use_last_tet) { Interpolator interpolator; //Referenz auf den letzten für die Interpolation gewählten Tetraeder vector<SensorPoint*>* last_tet = new vector<SensorPoint*>; //Referenz auf den aktuell für die Interpolation gewählten Tetraeder vector<SensorPoint*>* new_tet = new vector<SensorPoint*>; //Die Visualisierungsinformationen Visualization_info* vis_info = wxGetApp().getVisualizationInfo(); //Wurde der zuletzt verwendete Tetraeder initialisiert? bool last_tet_init = false; //Für alle Pixel im zu berechnenden Streifen... for (int x = 0; x < width; x++) { for (int y = startheight; y < startheight + delta_h; y++) { //Position des Pixels im 3D-Raum Vector3D* p = v0->copy(); //Verschiebung auf der X-Achse der Ebene im vergleich zum Ebenenmittelpunkt Vector3D* part_x = xvec->copy(); part_x->mult( x * info->mmperpixel / 1000. - width * info->mmperpixel / 2000); //Verschiebung auf der Y-Achse der Ebene im vergleich zum Ebenenmittelpunkt Vector3D* part_y = yvec->copy(); part_y->mult( y * info->mmperpixel / 1000. - height * info->mmperpixel / 2000); //Berechnen der Position des Pixels im 3D-Raum p->add(part_x); p->add(part_y); delete part_x; delete part_y; //Initialisieren des Pixels image->SetAlpha(x, y, 0); image->SetRGB(x, y, 0, 0, 0); value_img[y * width + x] = -300; //Für alle Materialien des objekts... for (unsigned int m = 0; m < obj->getMaterials()->size(); m++) { //Das aktuelle Material ObjectData::MaterialData* mat = &obj->getMaterials()->at(m); //Befindet sich der Punkt im aktuellen Material? if (pointInsideMesh(p, bases->at(m), info->in_volume_algorithm)) { //Ermitteln des Wertes für den Punkt int status = 0; interpolator.setMode(mat->interpolation_mode); float value = (float) getPointValue(status, sensor_data, p->getXYZ(), &interpolator, (last_tet_init && use_last_tet) ? last_tet : NULL, use_last_tet ? new_tet : 0); //Tausch der Speicherorte des Tetraeders, in dem sich der Punkt in diesem und im vorherigen Durchlauf befand vector<SensorPoint*>* temp; temp = last_tet; last_tet = new_tet; new_tet = temp; last_tet_init = true; //Speichern des Wertes in der Temperaturverteilung value_img[y * width + x] = value; //Berechnen der Farbe zum Temperaturwert float inverse_hue = (value - vis_info->min_visualisation_temp) / (vis_info->max_visualisation_temp + vis_info->min_visualisation_temp); float* color = hsvToRgb( (1.0 - clampHue(inverse_hue)) * .666, 1, 1); //Speichern des Wertes in der Grafik image->SetRGB(x, y, (unsigned char) (color[0] * 255), (unsigned char) (color[1] * 255), (unsigned char) (color[2] * 255)); delete color; image->SetAlpha(x, y, 255); break; } } delete p; } } delete new_tet; delete last_tet; //markieren des Threads als beendet *status_flag = 0; }
Colour Colour::getRandomFromHsvMean(glm::ivec3 _mean, glm::ivec3 _halfRange){ return hsvToRgb(glm::ivec3(_mean + glm::ivec3(sweet::NumberUtils::randomInt(-_halfRange.r, _halfRange.r), sweet::NumberUtils::randomInt(-_halfRange.g, _halfRange.g), sweet::NumberUtils::randomInt(-_halfRange.b, _halfRange.b)))); }
Colour Colour::getRandomFromHsvRange(glm::ivec3 _min, glm::ivec3 _max){ return hsvToRgb(glm::ivec3(sweet::NumberUtils::randomInt(_min.r, _max.r), sweet::NumberUtils::randomInt(_min.g, _max.g), sweet::NumberUtils::randomInt(_min.b, _max.b))); }
int main() { printf("fader_funcs_tst\n"); int led_start = 30; int led_end = 60; int led_range = led_end - led_start; for( int i = 0; i< led_range; i++ ) { int f = (256 * i) / led_range; // scale range to 0-255 int eased = ease8InOutApprox( f ) ; // get eased version int p = led_start + (eased * led_range)/256; printf("%d : %d : %d : %d\n", i, f, eased, p); } /* for( int p=ledpos_start; p < ledpos_end; p++ ) { int i = 256 * (p - ledpos_start)/ledpos_end; int easedledpos = p * ease8InOutCubic( i ) / 256; printf("%d : %d : %d\n", i, p, easedledpos ); } */ exit(0); rgb_t ctmp; for( int i=0; i< 255; i++ ) { ctmp.h = i; ctmp.s=255; ctmp.v = 255; hsvToRgb( &ctmp ); printf("%d: %d,%d,%d\n", i, ctmp.r, ctmp.g, ctmp.b ); } #if 0 rgb_t ctmp; // = { 255,255,255 }; //int ttmp = 15; //int ln = 5; int steps=10; ctmp.r=7; ctmp.g=100; ctmp.b=101; ledfader_setCurr( ctmp, 2); ctmp.r=203; ctmp.g=0; ctmp.b=0; steps = 1000; ledfader_setDest( ctmp, steps, 0 ); for( int i=0; i< steps+1; i++) { ledfader_update(); } #endif /* ctmp.r=25; ctmp.g=250; ctmp.b=55; ledfader.setDest( &ctmp, 50, ln ); for( int i=0; i< 55; i++) { ledfader.update(); } ctmp.r=125; ctmp.g=2; ctmp.b=255; ledfader.setDest( &ctmp, 20, ln ); for( int i=0; i< 25; i++) { ledfader.update(); } ctmp.r=255; ctmp.g=200; ctmp.b=0; ledfader.setDest( &ctmp, 1000, ln ); for( int i=0; i< 1010; i++) { ledfader.update(); } */ }
/** Returns a pointer to a new image, based on 'surface' but with changed hue. Changing the hue means to "rotate" the color spectrum. You can read more about the HSV color model on the Internet. This method is used to change the color of a sprite (e.g. a car or another object). I suggest to make the basic images in a red color-spectrum and create all other colors from it. For examples, please visit the Trophy homepage developer corner (http://trophy.sourceforge.net) \param hue Changing of hue: 0-360 \param saturation Changing of saturation: -100...100 \param value Changing of value (Color intensity): -100...100 */ CL_PixelBuffer CAImageManipulation::changeHSV( CL_PixelBuffer pixBufOriginal, int hue, int saturation, int value ) { CL_PixelBuffer pixbuf(pixBufOriginal.get_width(), pixBufOriginal.get_height(), pixBufOriginal.get_format()); pixBufOriginal.convert(pixbuf); CL_TextureFormat pf = pixbuf.get_format(); // Check that we handle this pixel format if(pf != CL_TextureFormat::cl_rgba8 && pf != CL_TextureFormat::cl_rgb8 && pf != CL_TextureFormat::cl_rgba4 ) { std::cout << "Unknow pixel format !" << pf << std::endl; return pixBufOriginal.copy(); } // Calc size in bytes: // int bpp = pixBufOriginal.get_bytes_per_pixel(); int size = pixbuf.get_width() * pixbuf.get_height() * bpp; pixbuf.lock(CL_BufferAccess::cl_access_read_write); unsigned char *data = (unsigned char*)pixbuf.get_data(); // Change hue: // int r, g, b, a(0); int h, s, v; for(int i=0; i<size; i+=bpp ) { if(pf == CL_TextureFormat::cl_rgba8) { a = data[i]; b = data[i+1]; g = data[i+2]; r = data[i+3]; } else if (pf == CL_TextureFormat::cl_rgb8) { std::cout << "TextureFormat : rgb888\n"; b = data[i]; g = data[i+1]; r = data[i+2]; } else if (pf == CL_TextureFormat::cl_rgba4) { std::cout << "TextureFormat : rgba4444\n"; r = data[i] && 0x0F; g = (data[i] && 0xF0) >> 4; b = data[i+1] && 0x0F; a = (data[i+1] && 0xF0) >> 4; } if( a!=0 && (r!=g || r!=b || g!=b) ) { rgbToHsv( r, g, b, &h, &s, &v ); h += hue; s += saturation; v += value; if( h > 360 ) h -= 360; if( s > 255 ) s = 255; if( v > 255 ) v = 255; if( h < 0 ) h += 360; if( s < 0 ) s = 0; if( v < 0 ) v = 0; hsvToRgb( h, s, v, &r, &g, &b ); if(pf == CL_TextureFormat::cl_rgba8) { data[i] = a; data[i+1] = b; data[i+2] = g; data[i+3] = r; } else if (pf == CL_TextureFormat::cl_rgb8) { data[i] = b; data[i+1] = g; data[i+2] = r; } else if (pf == CL_TextureFormat::cl_rgba4) { data[i] = r + (g << 4); data[i+1] = b + (a << 4); } } }
int main() { if (!initWindow(WINDOW_WIDTH, WINDOW_HEIGHT)) { std::cerr << "Failed to initialize window.\n"; return 1; } int tex_width, tex_height; GLuint main_texture = loadTexture(&tex_width, &tex_height, "graphics.png"); assert(main_texture != 0); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GLuint shader_program = loadShaderProgram(); glUseProgram(shader_program); GLuint u_view_matrix_location = glGetUniformLocation(shader_program, "u_view_matrix"); GLfloat view_matrix[9] = { 2.0f/WINDOW_WIDTH, 0.0f, -1.0f, 0.0f, -2.0/WINDOW_HEIGHT, 1.0f, 0.0f, 0.0f, 1.0f }; glUniformMatrix3fv(u_view_matrix_location, 1, GL_TRUE, view_matrix); GLuint u_texture_location = glGetUniformLocation(shader_program, "u_texture"); glUniform1i(u_texture_location, 0); CHECK_GL_ERROR; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, main_texture); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); CHECK_GL_ERROR; SpriteBuffer sprite_buffer; sprite_buffer.tex_width = static_cast<float>(tex_width); sprite_buffer.tex_height = static_cast<float>(tex_height); GLuint vao_id; glGenVertexArrays(1, &vao_id); glBindVertexArray(vao_id); GLuint vbo_id; glGenBuffers(1, &vbo_id); glBindBuffer(GL_ARRAY_BUFFER, vbo_id); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), reinterpret_cast<void*>(offsetof(VertexData, pos_x))); glVertexAttribPointer(1, 2, GL_FLOAT, GL_TRUE, sizeof(VertexData), reinterpret_cast<void*>(offsetof(VertexData, tex_s))); glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VertexData), reinterpret_cast<void*>(offsetof(VertexData, color))); for (int i = 0; i < 3; ++i) glEnableVertexAttribArray(i); GLuint ibo_id; glGenBuffers(1, &ibo_id); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id); /////////////////////////// // Initialize game state // /////////////////////////// GameState game_state; RandomGenerator& rng = game_state.rng; rng.seed(123); { Paddle& p = game_state.paddle; p.pos_x = WINDOW_WIDTH / 2; p.pos_y = WINDOW_HEIGHT - 32; p.rotation = 0; } Sprite paddle_spr; paddle_spr.setImg(0, 0, 64, 16); Sprite gem_spr; gem_spr.setImg(0, 16, 16, 16); static const int GEM_SPAWN_INTERVAL = 60*5; int gem_spawn_timer = GEM_SPAWN_INTERVAL; CHECK_GL_ERROR; //////////////////// // Main game loop // //////////////////// bool running = true; while (running) { /* Update paddle */ { Paddle& paddle = game_state.paddle; fixed24_8 paddle_speed(0); fixed8_24 rotation = 0; if (glfwGetKey(GLFW_KEY_LEFT)) { paddle_speed -= PADDLE_MOVEMENT_SPEED; rotation -= PADDLE_ROTATION_RATE; } if (glfwGetKey(GLFW_KEY_RIGHT)) { paddle_speed += PADDLE_MOVEMENT_SPEED; rotation += PADDLE_ROTATION_RATE; } if (rotation == 0) { paddle.rotation = stepTowards(paddle.rotation, fixed8_24(0), PADDLE_ROTATION_RETURN_RATE); } else { paddle.rotation = clamp(-PADDLE_MAX_ROTATION, paddle.rotation + rotation, PADDLE_MAX_ROTATION); } paddle.pos_x += paddle_speed; } /* Spawn new gems */ if (--gem_spawn_timer == 0) { gem_spawn_timer = GEM_SPAWN_INTERVAL; Gem b; b.pos_x = randRange(rng, WINDOW_WIDTH * 1 / 6, WINDOW_WIDTH * 5 / 6); b.pos_y = -10; b.vel_x = b.vel_y = 0; b.score_value = Gem::INITIAL_VALUE; game_state.gems.push_back(b); } /* Update balls */ for (unsigned int i = 0; i < game_state.gems.size(); ++i) { Gem& ball = game_state.gems[i]; ball.vel_y += fixed16_16(0, 1, 8); ball.pos_x += fixed24_8(ball.vel_x); ball.pos_y += fixed24_8(ball.vel_y); collideBallWithBoundary(ball); for (unsigned int j = i + 1; j < game_state.gems.size(); ++j) { collideBallWithBall(ball, game_state.gems[j]); } collideBallWithPaddle(ball, game_state.paddle); } /* Clean up dead gems */ remove_if(game_state.gems, [](const Gem& gem) { return gem.pos_y > WINDOW_HEIGHT + 128 && gem.vel_y > 0; }); /* Draw scene */ sprite_buffer.clear(); paddle_spr.setPos(game_state.paddle.pos_x.integer(), game_state.paddle.pos_y.integer()); sprite_buffer.append(paddle_spr, game_state.paddle.getSpriteMatrix()); for (const Gem& gem : game_state.gems) { gem_spr.setPos(gem.pos_x.integer() - gem_spr.img_w / 2, gem.pos_y.integer() - gem_spr.img_h / 2); float r, g, b; hsvToRgb(mapScoreToHue(gem.score_value), 1.0f, 1.0f, &r, &g, &b); gem_spr.color = makeColor(uint8_t(r*255 + 0.5f), uint8_t(g*255 + 0.5f), uint8_t(b*255 + 0.5f), 255); sprite_buffer.append(gem_spr); } // HUD { static const int HUD_X_POS = 1; static const int HUD_Y_POS = 1; Sprite hud_spr; hud_spr.setImg(64, 0, 29, 11); hud_spr.setPos(HUD_X_POS, HUD_Y_POS); sprite_buffer.append(hud_spr); hud_spr.setImg(64, 12, 29, 11); hud_spr.setPos(HUD_X_POS, HUD_Y_POS + 13); sprite_buffer.append(hud_spr); std::string score_text = std::to_string(game_state.score); FontInfo font('0', 40, 24, 8, 12); drawText(HUD_X_POS + 31, HUD_Y_POS, score_text, sprite_buffer, font); } /* Submit sprites */ // More superfluous drawcalls to change the GPU into high-performance mode? Sure, why not. glClear(GL_COLOR_BUFFER_BIT); for (int i = 0; i < 1000; ++i) { sprite_buffer.upload(); sprite_buffer.draw(); } for (const Sprite& spr : debug_sprites) { sprite_buffer.append(spr); } debug_sprites.clear(); glClear(GL_COLOR_BUFFER_BIT); sprite_buffer.upload(); sprite_buffer.draw(); glfwSwapBuffers(); running = running && glfwGetWindowParam(GLFW_OPENED); CHECK_GL_ERROR; } glfwCloseWindow(); glfwTerminate(); }