I am making a program that creates lines, how can I erase a line? Is there a function for it?
I have already tried using SDL_RenderClear() but it did not work.
(please note that i am a beginner and that im NOT native american, also i only am 10 years old so explain in a simple way.)
Here is my line creating code:
#include <iostream>
#include <SDL.h>
using namespace std;
int main( int argc, char * argv[] )
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *janela = NULL;
SDL_Renderer *renderer = NULL;
bool roda = true;
SDL_Event evento;
int x;
int y;
int x2;
int y2;
janela = SDL_CreateWindow( "janela" , SDL_WINDOWPOS_CENTERED , SDL_WINDOWPOS_CENTERED ,500 , 500 , SDL_WINDOW_RESIZABLE);
renderer = SDL_CreateRenderer(janela , -1 , SDL_RENDERER_ACCELERATED);
while (roda) {
SDL_Event evento;
while (SDL_PollEvent(&evento)) {
switch(evento.type){
case SDL_QUIT:
roda = false;
break;
case SDL_MOUSEBUTTONDOWN:{
x = evento.motion.x;
y = evento.motion.y;
break;}
case SDL_MOUSEBUTTONUP:
while(roda){
x2 = evento.motion.x;
y2 = evento.motion.y;
SDL_SetRenderDrawColor(renderer , 255 , 0 , 0 , 255);
SDL_SetRenderDrawColor(renderer , 125 , 234 , 253 , 255);
SDL_RenderDrawLine(renderer , x , y , x2 , y2);
SDL_RenderPresent(renderer);
break;}
case SDL_KEYDOWN:{
switch(evento.key.keysym.sym){
case SDLK_b:{
SDL_RenderClear(renderer);
}
}
}
}
}
}
SDL_DestroyWindow(janela);
janela = NULL;
SDL_DestroyRenderer(renderer);
renderer = NULL;
SDL_Quit();
return 1;
}
What I expect is the lines to be erased but it did not happen.
Typical main loop is basically this:
while(!quit) {
while(pool_event()) {
// change state to react to event
}
clear_previous_frame();
for each line {
draw_line();
}
present();
}
So you should always clear and redraw your lines, adding new line state if events says so (but not drawing it yet - event processing shouldn't do that, or it becomes very compilcated). It is problemmatic to keep previous frame's contents and just add more lines; short explaination is because SDL_RenderPresent documentation says The backbuffer should be considered invalidated after each present (and long explaination is basically a list of reasons why it says so).
To keep track of lines to draw you need to save them somewhere. std::vector could be a simple option, if your requirements aren't against it.
To sum it up, your question's modified code with a bit of comments:
#include <vector>
#include <SDL.h>
struct line {
int x0, y0, x1, y1;
};
int main( int argc, char * argv[] )
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *janela = NULL;
SDL_Renderer *renderer = NULL;
bool roda = true;
int x;
int y;
janela = SDL_CreateWindow( "janela" , SDL_WINDOWPOS_CENTERED , SDL_WINDOWPOS_CENTERED ,500 , 500 , SDL_WINDOW_RESIZABLE);
renderer = SDL_CreateRenderer(janela , -1 , SDL_RENDERER_ACCELERATED);
std::vector<line> lines;
while (roda) {
SDL_Event evento;
while (SDL_PollEvent(&evento)) {
switch(evento.type){
case SDL_QUIT:
roda = false;
break;
case SDL_MOUSEBUTTONDOWN:
// save starting coordinates
x = evento.motion.x;
y = evento.motion.y;
break;
case SDL_MOUSEBUTTONUP: {
// add new line to draw
line l = { x, y, evento.motion.x, evento.motion.y };
lines.push_back(l);
} break;
case SDL_KEYDOWN:
if(evento.key.keysym.sym == SDLK_b) {
// drop lines
lines.resize(0);
}
break;
}
}
// clear previous contents - in most cases, screen content is
// invalidated after RenderPresent and you need to draw again
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); // your 'clear' colour
SDL_RenderClear(renderer);
// draw all accumulated lines
SDL_SetRenderDrawColor(renderer, 125, 234, 253, 255); // your lines colour
for(const line &l : lines) {
SDL_RenderDrawLine(renderer, l.x0, l.y0, l.x1, l.y1);
}
// all drawn - present
SDL_RenderPresent(renderer);
}
SDL_DestroyWindow(janela);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0; // 0 is 'success' return code, non-0 is failure
}
Related
I constantly get this error, no matter what I'm doing... I have an ILI9488 with 4-wire SPI and a GT911 capacitive Touch driver on an ESP32 (2MB, no PSRAM, arduino core).
this is my main.ino-file:
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <Wire.h>
#include "Goodix.h"
#define INT_PIN 26
#define RST_PIN 15
#define SDA_PIN 22
#define SCL_PIN 16
Goodix touch = Goodix();
#define DISPLAY_BUF_SIZE 480 * 10
static uint16_t display_widht = 480;
static uint16_t display_height = 320;
TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
bool touched = false;
GTPoint touchDat;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[ DISPLAY_BUF_SIZE];
lv_disp_drv_t disp_drv; //display driver
lv_indev_drv_t touch_drv; //touchpad driver
void my_disp_flush( lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p ){
uint32_t w = ( area->x2 - area->x1 + 1 );
uint32_t h = ( area->y2 - area->y1 + 1 );
tft.startWrite();
tft.setAddrWindow( area->x1, area->y1, w, h );
tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );
tft.endWrite();
lv_disp_flush_ready( disp );
}
void handleTouch(int8_t contacts, GTPoint* points) {
Serial.printf("Contacts: %d\n", contacts);
if(contacts > 0) touched = true;
else touched = false;
for (uint8_t i = 0; i < contacts; i++) {
touchDat = points[0];
Serial.printf("C%d: %d %d \n", points[i].trackId, points[i].x, points[i].y);
}
}
/*Read the touchpad*/
void my_touchpad_read( lv_indev_drv_t * touch_drv, lv_indev_data_t * data ){
if( !touched ) //kein Touch
{
data->state = LV_INDEV_STATE_REL;
}
else //touch!
{
data->state = LV_INDEV_STATE_PR;
/*Set the coordinates*/
data->point.x = touchDat.x;
data->point.y = touchDat.y;
}
}
void i2cInit(){
Wire.setPins(SDA_PIN, SCL_PIN);
Wire.setClock(400000);
Wire.begin();
delay(100);
}
void touchInit() {
touch.setHandler(handleTouch);
touch.setRes(display_widht, display_height);
touch.setRotation(3);
touch.begin(INT_PIN, RST_PIN, GOODIX_I2C_ADDR_28);
Serial.print("Check ACK on addr request on 0x");
Serial.print(touch.i2cAddr, HEX);
Wire.beginTransmission(touch.i2cAddr);
if (!Wire.endTransmission()) {
Serial.println(": SUCCESS");
} else {
Serial.print(": ERROR!");
}
}
void tftInit(){
tft.begin();
tft.setRotation(3);
lv_disp_draw_buf_init( &draw_buf, buf, NULL, DISPLAY_BUF_SIZE ); //init draw Buffer
/*Initialize the display*/
static lv_disp_drv_t disp_drv;
lv_disp_drv_init( &disp_drv );
/*Change the following line to your display resolution*/
disp_drv.hor_res = display_widht;
disp_drv.ver_res = display_height;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register( &disp_drv );
/*Initialize the input device driver*/
static lv_indev_drv_t touch_drv;
lv_indev_drv_init( &touch_drv );
touch_drv.type = LV_INDEV_TYPE_POINTER;
touch_drv.read_cb = my_touchpad_read;
lv_indev_drv_register( &touch_drv );
//create simple label
lv_obj_t *label = lv_label_create( lv_scr_act() );
lv_label_set_text( label, "Hello World!!" );
lv_obj_align( label, LV_ALIGN_CENTER, 0, 0 );
}
void setup() {
Serial.begin(115200); /* prepare for possible serial debug */
i2cInit();
touchInit(); //initialize touch
lv_init();
}
void loop() {
touch.loop();
lv_task_handler(); /* let the GUI do its work */
delay(5);
}
these are my main.ino and lv_config.h-files:
https://gist.github.com/kokospalme/a65448c1d10704066b9c6d2350c84a6d
even if I change LV_MEM_SIZE to something small like 1 or 10, I get the error, that " region `dram0_0_seg' overflowed by 22272 bytes". What am I doing wrong?
The code is building successfully but when I run the code I have the following error -
The following is a new check for GLUT 3.0; update your code.
GLUT: Fatal Error in D:\6th Sem\4. CG UCS505\EasyAlgo\Project1\Debug\Project1.exe: redisplay needed for window 1, but no display callback.
I've tried everything but am not able to figure it out, am new with open gl and vs. Thank you for your help.
Here is the .cpp file code -
source.cpp
#include <GL/glut.h>
#include <debug.hpp>
#include <config.hpp>
#include <blobs.hpp>
#include <fonts.hpp>
#include <draw.hpp>
#include <highlight.hpp>
#include <animation.hpp>
#include <unistd.h>
#include <iostream>
using namespace std;
unsigned short mainWindow, subWindow1, subWindow2;
void Init(float, float, float);
void Init(float, float, float, int, int);
void mainInit();
void display();
void onClick(int, int, int, int);
void keyPress(unsigned char, int, int);
int main(int argc, char** argv)
{
#ifdef DEBUG
mode = "InsertionSort";
b1.bv.resize(7, blobs());
int rad[7] = { 28,32,20,28,36,45,31 };
for (int p = 0; p < 7; p++)
b1.bv[p].radius = (float)rad[p];
b1.min = 20;
b1.max = 45;
#endif
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(WindowWidth, WindowHeight);
std::string title = "AlgoLucidator " + AL_VERSION;
mainWindow = glutCreateWindow(title.c_str());
glutPositionWindow(WIN_POS_X, WIN_POS_Y);
mainInit();
glutMouseFunc(onClick);
glutKeyboardFunc(keyPress);
subWindow1 = glutCreateSubWindow(mainWindow, 0, 0, WindowWidth / 4, WindowHeight);
Init(0.80f, 0.80f, 0.60f);
glutKeyboardFunc(keyPress);
glutDisplayFunc(display);
subWindow2 = glutCreateSubWindow(mainWindow, WindowWidth / 4, 0, 3 * WindowWidth / 4, WindowHeight);
Init(0.65f, 0.75f, 0.70f);
std::string mainInstruct = "Press 1. InsertionSort 2. BubbleSort 3. Dijkstra";
printText(0, 0, 0, -(5 * mainInstruct.size()), 540, mainInstruct);
glutMouseFunc(onClick);
glutKeyboardFunc(keyPress);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
void Init(float r, float g, float b)
{
int CurrWindowWidth = glutGet(GLUT_WINDOW_WIDTH);
int CurrWindowHeight = glutGet(GLUT_WINDOW_HEIGHT);
glClearColor(r, g, b, 1);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
gluOrtho2D(-CurrWindowWidth, CurrWindowWidth, -CurrWindowHeight, CurrWindowHeight);
drawTitle(CurrWindowWidth, CurrWindowHeight);
}
void Init(float r, float g, float b, int width, int height)
{
glClearColor(r, g, b, 1);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
gluOrtho2D(-width, width, -height, height);
drawTitle(width, height);
}
void mainInit()
{
int CurrWindowWidth = glutGet(GLUT_WINDOW_WIDTH);
int CurrWindowHeight = glutGet(GLUT_WINDOW_HEIGHT);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0, CurrWindowWidth, 0, CurrWindowHeight);
glClearColor(0, 0, 0, 0.80f);
glClear(GL_COLOR_BUFFER_BIT);
}
void display()
{
glFlush();
}
void onClick(int button, int state, int oldx, int oldy)
{}
void keyPress(unsigned char key, int x, int y)
{
int activeWindow = glutGetWindow();
switch (key)
{
case 13: if (b1.pushreq)
{
b1.bv.push_back(blobs((float)base_radius));
}
if (activeWindow != subWindow2)
glutSetWindow(subWindow2);
if (mode == "InsertionSort")
{
drawInsertionSort();
}
else if (mode == "BubbleSort")
{
drawBubbleSort();
}
break;
case 27: glutDestroyWindow(mainWindow); //Esc
break;
case 49: mode = "InsertionSort";
b1.reset();
glutSetWindow(subWindow2);
glutMouseFunc(onClick2);
Init2(0.65f, 0.75f, 0.70f);
drawTitle3(960, 640);
break;
case 50: mode = "BubbleSort";
glutSetWindow(subWindow2);
glutMouseFunc(onClick3);
glutIdleFunc(display);
Init3(0.65f, 0.75f, 0.70f);
drawTitle4(960, 640);
break;
default:;
}
}
The error message is pretty much exactly telling what's wrong and how to fix it (QFT):
The following is a new check for GLUT 3.0; update your code. GLUT: Fatal Error in (…) Project1.exe: redisplay needed for window 1, but no display callback.
For first window you create, window one, the one created with glutCreateWindow you don't specify a display callback:
mainWindow = glutCreateWindow(title.c_str());
glutPositionWindow(WIN_POS_X, WIN_POS_Y);
mainInit();
glutMouseFunc(onClick);
glutKeyboardFunc(keyPress);
/// <<<<<<<< something is missing here
subWindow1 = glutCreateSubWindow(mainWindow, 0, 0, WindowWidth / 4, WindowHeight);
Give that first window you create a display callback and the error will go away.
On a second note: Nothing of what's happening in the …Init functions is initialization at all. OpenGL is a state machine, and everything done in …Init is state prepration that ought to happen at the start of rendering a frame.
The same problem happens in Borland C++Builder 6 and Embarcadero C++Builder 2010.
When I try to invert an image, the form freezes for about 5 seconds and nothing happens. When I click again, the image is inverted within a blink of an eye, and again, again...
To reproduce, create a form with a TImage and two TButton's using this code:
//---------------------------------------------------------------------------
#include <vcl.h>
#include <jpeg.hpp>
#pragma hdrstop
#pragma package(smart_init)
#pragma resource "*.dfm"
#include "Unit1.h"
TForm1 *Form1;
Graphics::TBitmap *CurrentBitmap;
bool bLoaded = false;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {
CurrentBitmap = new Graphics::TBitmap;
}
//---------------------------------------------------------------------------
bool __fastcall Invert( TImage *img ) {
if( bLoaded ) {
double Scale, ScaleW, ScaleH;
Graphics::TBitmap *bmp = new Graphics::TBitmap;
bmp->Assign( CurrentBitmap );
DWORD **pixel = new DWORD*[bmp->Height];
for( long y=0; y<bmp->Height; y++ ) {
pixel[y] = (DWORD*)(bmp->ScanLine[y]);
for( long x=0; x<bmp->Width; x++ ) {
if( pixel[y][x] == clBlack ) {
pixel[y][x] = clWhite;
} else if( pixel[y][x] == clWhite ) {
pixel[y][x] = clBlack;
}
}
}
delete[] pixel;
ScaleW = (double)bmp->Width / img->ClientWidth;
ScaleH = (double)bmp->Height / img->ClientHeight;
if( ScaleW > ScaleH ) {
Scale = ScaleW;
} else {
Scale = ScaleH;
}
CurrentBitmap->Assign( bmp );
img->Picture->Bitmap->Canvas->StretchDraw(Rect(0, 0, bmp->Width/Scale, bmp->Height/Scale), bmp );
delete bmp;
return true;
} else {
return false;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender) {
TJPEGImage *jpg = new TJPEGImage();
jpg->LoadFromFile( "V:\\CBuilder\\BCB10\\GerberTest\\Testdata\\GerberTest.dpi2400.mskcmp.jpg" );
CurrentBitmap->Width = jpg->Width;
CurrentBitmap->Height = jpg->Height;
CurrentBitmap->Canvas->StretchDraw(Rect(0, 0, jpg->Width, jpg->Height), jpg );
bLoaded = true;
double Scale, ScaleW, ScaleH;
ScaleW = (double)jpg->Width / Image1->ClientWidth;
ScaleH = (double)jpg->Height / Image1->ClientHeight;
if( ScaleW > ScaleH ) {
Scale = ScaleW;
} else {
Scale = ScaleH;
}
Image1->Canvas->StretchDraw(Rect(0, 0, jpg->Width/Scale, jpg->Height/Scale), jpg );
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender) {
Invert( Image1 );
}
I cannot explain why the application freezes, or what the code is doing during the 5 second delay.
Like Remy Lebeau mentioned you should set the PixelFormat. I tried your solution which did not seems to invert images properly. Below you find a solution which should work properly.
#include <JPEG.hpp>
Byte __fastcall IntToByte(int AValue)
{
if (AValue > 255)
return 255;
else if (AValue < 0)
return 0;
else
return AValue;
}
// ---------------------------------------------------------------------------
void __fastcall InvertBitmap(Graphics::TBitmap *ABitmap)
{
Byte *p0;
int red, green, blue;
for (int y = 0; y < ABitmap->Height; y++) {
p0 = (Byte*) ABitmap->ScanLine[y];
for (int x = 0; x < ABitmap->Width; x++) {
red = p0[x * 3];
green = p0[x * 3 + 1];
blue = p0[x * 3 + 2];
// invert
red = 255 - red;
green = 255 - green;
blue = 255 - blue;
p0[x * 3] = IntToByte(red);
p0[x * 3 + 1] = IntToByte(green);
p0[x * 3 + 2] = IntToByte(blue);
}
}
}
// ---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Screen->Cursor = crHourGlass;
TJPEGImage *jpeg = new TJPEGImage();
Graphics::TBitmap *bitmap = new Graphics::TBitmap();
try {
jpeg->LoadFromFile("**YOUR-JPEG-FILE**");
bitmap->SetSize(jpeg->Width, jpeg->Height);
bitmap->Canvas->Draw(0, 0, jpeg);
bitmap->PixelFormat = pf24bit;
InvertBitmap(bitmap);
Image1->Picture->Bitmap->Assign(bitmap);
}
__finally {
jpeg->Free();
bitmap->Free();
}
Screen->Cursor = crDefault;
}
// ---------------------------------------------------------------------------
I've been trying to implement a systray icon using straight C and Xlib, going along with the freedesktop specification [0]. I can't seem to get my Window to embed into my desktop manager's systray[1], while other apps seem to be able to do it. I am not sure how to go forward debugging this, but I've provided minimal sample code below.
I haven't been able to find any sample code using straight Xlib and C, and all the suggestions I've seen have been with regard to some framework like Gtk/Qt/Mono/whatever, but I want to understand what is supposed to be happening here as per the spec, and what I'm doing wrong.
#include <X11/Xutil.h>
#include <string.h>
#define MIN(A, B) ((A) < (B) ? (A) : (B))
/* --------- XEMBED and systray stuff */
#define SYSTEM_TRAY_REQUEST_DOCK 0
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
static int trapped_error_code = 0;
static int (*old_error_handler) (Display *, XErrorEvent *);
static int
error_handler(Display *display, XErrorEvent *error) {
trapped_error_code = error->error_code;
return 0;
}
void
trap_errors(void) {
trapped_error_code = 0;
old_error_handler = XSetErrorHandler(error_handler);
}
int
untrap_errors(void) {
XSetErrorHandler(old_error_handler);
return trapped_error_code;
}
void
send_systray_message(Display* dpy, Window w, long message, long data1, long data2, long data3) {
XEvent ev;
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
ev.xclient.window = w;
ev.xclient.message_type = XInternAtom (dpy, "_NET_SYSTEM_TRAY_OPCODE", False );
ev.xclient.format = 32;
ev.xclient.data.l[0] = CurrentTime;
ev.xclient.data.l[1] = message;
ev.xclient.data.l[2] = data1;
ev.xclient.data.l[3] = data2;
ev.xclient.data.l[4] = data3;
trap_errors();
XSendEvent(dpy, w, False, NoEventMask, &ev);
XSync(dpy, False);
if (untrap_errors()) {
/* Handle errors */
}
}
/* ------------ Regular X stuff */
int
main(int argc, char **argv) {
int width, height;
XWindowAttributes wa;
XEvent ev;
Display *dpy;
int screen;
Window root, win;
/* init */
if (!(dpy=XOpenDisplay(NULL)))
return 1;
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
if(!XGetWindowAttributes(dpy, root, &wa))
return 1;
width = height = MIN(wa.width, wa.height);
/* create window */
win = XCreateSimpleWindow(dpy, root, 0, 0, width, height, 0, 0, 0xFFFF9900);
send_systray_message(dpy, win, SYSTEM_TRAY_REQUEST_DOCK, win, 0, 0);
XMapWindow(dpy, win);
XSync(dpy, False);
/* run */
while(1) {
while(XPending(dpy)) {
XNextEvent(dpy, &ev); /* just waiting until we error because window closed */
}
}
}
Any help would be greatly appreciated. I think this problem is language-agnostic, and more to do with me misunderstanding the protocols, so answers in any language are acceptable, as long as they help me iron out this XEvent stuff.
[0] https://specifications.freedesktop.org/systemtray-spec/systemtray-spec-0.2.html
[1] I'm using dwm with the systray patch http://dwm.suckless.org/patches/systray
You are sending the message to a wrong window. The documentation isn't really helpful, it makes no sense whatsoever to send a tray embed message to your own window!. You need to send it to the tray window.
Here's a a fixed send_systray_message
void
send_systray_message(Display* dpy, long message, long data1, long data2, long data3) {
XEvent ev;
Atom selection_atom = XInternAtom (dpy,"_NET_SYSTEM_TRAY_S0",False);
Window tray = XGetSelectionOwner (dpy,selection_atom);
if ( tray != None)
XSelectInput (dpy,tray,StructureNotifyMask);
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
ev.xclient.window = tray;
ev.xclient.message_type = XInternAtom (dpy, "_NET_SYSTEM_TRAY_OPCODE", False );
ev.xclient.format = 32;
ev.xclient.data.l[0] = CurrentTime;
ev.xclient.data.l[1] = message;
ev.xclient.data.l[2] = data1; // <--- your window is only here
ev.xclient.data.l[3] = data2;
ev.xclient.data.l[4] = data3;
trap_errors();
XSendEvent(dpy, tray, False, NoEventMask, &ev);
XSync(dpy, False);
usleep(10000);
if (untrap_errors()) {
/* Handle errors */
}
}
and a call to it
send_systray_message(dpy, SYSTEM_TRAY_REQUEST_DOCK, win, 0, 0); // pass win only once
Credits: http://distro.ibiblio.org/vectorlinux/Uelsk8s/GAMBAS/gambas-svn/gambas2/gb.gtk/src/gtrayicon.cpp
I can find questions/answers for iPhone/Windows but none for X11.
Also if there is anyone with a ton of OpenGL experience who can explain the general concepts involved for any windowing system?
Yes it is possible. I modified a example program written by fungus to create a RGBA OpenGL window. If a compositor is enabled the results look like in the video I posted here: http://www.youtube.com/watch?v=iHZfH1Qhonk
/*------------------------------------------------------------------------
The simplest possible Linux OpenGL program? Maybe...
Modification for creating a RGBA window (transparency with compositors)
by Wolfgang 'datenwolf' Draxinger
(c) 2002 by FTB. See me in comp.graphics.api.opengl
(c) 2011 Wolfgang Draxinger. See me in comp.graphics.api.opengl and on StackOverflow
License agreement: This source code is provided "as is". You
can use this source code however you want for your own personal
use. If you give this source code to anybody else then you must
leave this message in it.
--
<\___/>
/ O O \
\_____/ FTB.
--
datenwolf
------------------------------------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <GL/glx.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xrender.h>
typedef struct
{
Visual *visual;
VisualID visualid;
int screen;
unsigned int depth;
int klass;
unsigned long red_mask;
unsigned long green_mask;
unsigned long blue_mask;
int colormap_size;
int bits_per_rgb;
} XVisualInfo_CPP;
/*------------------------------------------------------------------------
Something went horribly wrong
------------------------------------------------------------------------*/\
static void fatalError(const char *why)
{
fprintf(stderr, "%s", why);
exit(0x666);
}
/*------------------------------------------------------------------------
Global vars
------------------------------------------------------------------------*/
static int Xscreen;
static Atom del_atom;
static Colormap cmap;
static Display *Xdisplay;
static XVisualInfo_CPP *visual;
static XRenderPictFormat *pictFormat;
static GLXFBConfig *fbconfigs, fbconfig;
static int numfbconfigs;
static GLXContext RenderContext;
static Window Xroot, WindowHandle, GLXWindowHandle;
static int width, height; /* Size of the window */
int const tex_width=512;
int const tex_height=512;
static GLuint texture;
static int VisData[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_DOUBLEBUFFER, True,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_ALPHA_SIZE, 1,
GLX_DEPTH_SIZE, 1,
None
};
/*------------------------------------------------------------------------
Create a window
------------------------------------------------------------------------*/
static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg)
{
return (e->type == MapNotify) && (e->xmap.window == *(Window*)arg);
}
static void createTheWindow()
{
XEvent event;
int x,y, attr_mask;
XSizeHints hints;
XWMHints *StartupState;
XTextProperty textprop;
XSetWindowAttributes attr;
static char *title = "FTB's little OpenGL example";
/* Connect to the X server */
Xdisplay = XOpenDisplay(NULL);
if (!Xdisplay) {
fatalError("Couldn't connect to X server\n");
}
Xscreen = DefaultScreen(Xdisplay);
Xroot = RootWindow(Xdisplay, Xscreen);
fbconfigs = glXChooseFBConfig(Xdisplay, Xscreen, VisData, &numfbconfigs);
for(int i = 0; i<numfbconfigs; i++) {
visual = (XVisualInfo_CPP*) glXGetVisualFromFBConfig(Xdisplay, fbconfigs[i]);
if(!visual)
continue;
pictFormat = XRenderFindVisualFormat(Xdisplay, visual->visual);
if(!pictFormat)
continue;
if(pictFormat->direct.alphaMask > 0) {
fbconfig = fbconfigs[i];
break;
}
}
/* Create a colormap - only needed on some X clients, eg. IRIX */
cmap = XCreateColormap(Xdisplay, Xroot, visual->visual, AllocNone);
/* Prepare the attributes for our window */
attr.colormap = cmap;
attr.border_pixel = 0;
attr.event_mask =
StructureNotifyMask |
EnterWindowMask |
LeaveWindowMask |
ExposureMask |
ButtonPressMask |
ButtonReleaseMask |
OwnerGrabButtonMask |
KeyPressMask |
KeyReleaseMask;
attr.background_pixmap = None;
attr_mask =
CWBackPixmap|
CWColormap|
CWBorderPixel|
CWEventMask; /* What's in the attr data */
/* Create the window */
width = DisplayWidth(Xdisplay, DefaultScreen(Xdisplay))/2;
height = DisplayHeight(Xdisplay, DefaultScreen(Xdisplay))/2;
x=width/2, y=height/2;
/* Create the window */
WindowHandle = XCreateWindow( Xdisplay, /* Screen */
Xroot, /* Parent */
x, y, width, height,/* Position */
1,/* Border */
visual->depth,/* Color depth*/
InputOutput,/* klass */
visual->visual,/* Visual */
attr_mask, &attr);/* Attributes*/
if( !WindowHandle ) {
fatalError("Couldn't create the window\n");
}
/* Configure it... (ok, ok, this next bit isn't "minimal") */
textprop.value = (unsigned char*)title;
textprop.encoding = XA_STRING;
textprop.format = 8;
textprop.nitems = strlen(title);
hints.x = x;
hints.y = y;
hints.width = width;
hints.height = height;
hints.flags = USPosition|USSize;
StartupState = XAllocWMHints();
StartupState->initial_state = NormalState;
StartupState->flags = StateHint;
XSetWMProperties(Xdisplay, WindowHandle,&textprop, &textprop,/* Window title/icon title*/
NULL, 0,/* Argv[], argc for program*/
&hints, /* Start position/size*/
StartupState,/* Iconised/not flag */
NULL);
XFree(StartupState);
/* Open it, wait for it to appear */
XMapWindow(Xdisplay, WindowHandle);
XIfEvent(Xdisplay, &event, WaitForMapNotify, (char*)&WindowHandle);
/* Set the kill atom so we get a message when the user tries to close the window */
if ((del_atom = XInternAtom(Xdisplay, "WM_DELETE_WINDOW", 0)) != None) {
XSetWMProtocols(Xdisplay, WindowHandle, &del_atom, 1);
}
}
/*------------------------------------------------------------------------
Create the OpenGL rendering context
------------------------------------------------------------------------*/
static void createTheRenderContext()
{
/* See if we can do OpenGL on this visual */
int dummy;
if (!glXQueryExtension(Xdisplay, &dummy, &dummy)) {
fatalError("OpenGL not supported by X server\n");
}
/* Create the OpenGL rendering context */
RenderContext = glXCreateNewContext(Xdisplay, fbconfig, GLX_RGBA_TYPE, 0, True);
if (!RenderContext) {
fatalError("Failed to create a GL context\n");
}
GLXWindowHandle = glXCreateWindow(Xdisplay, fbconfig, WindowHandle, NULL);
/* Make it current */
if (!glXMakeContextCurrent(Xdisplay, GLXWindowHandle, GLXWindowHandle, RenderContext)) {
fatalError("glXMakeCurrent failed for window\n");
}
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
}
/*------------------------------------------------------------------------
Window messages
------------------------------------------------------------------------*/
static int updateTheMessageQueue()
{
XEvent event;
XConfigureEvent *xc;
while (XPending(Xdisplay))
{
XNextEvent(Xdisplay, &event);
switch (event.type)
{
case ClientMessage:
if (event.xclient.data.l[0] == del_atom)
{
return 0;
}
break;
case ConfigureNotify:
xc = &(event.xconfigure);
width = xc->width;
height = xc->height;
break;
}
}
return 1;
}
/*------------------------------------------------------------------------
Redraw the window
------------------------------------------------------------------------*/
float const light_dir[]={1,1,1,0};
float const light_color[]={1,0.95,0.9,1};
static void redrawTheWindow()
{
int size;
static float a=0;
static float b=0;
static float c=0;
glViewport(0,0,width,height);
/* Clear the screen */
// glClearColor(0.750,0.750,1.0,0.5);
glClearColor(0.0,0.0,0.0,0.);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, (float)width/(float)height, 1, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glLightfv(GL_LIGHT0, GL_POSITION, light_dir);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color);
glTranslatef(0,0,-5);
glRotatef(a, 1, 0, 0);
glRotatef(b, 0, 1, 0);
glRotatef(c, 0, 0, 1);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
glutSolidTeapot(1);
a=fmod(a+0.1, 360.);
b=fmod(b+0.5, 360.);
c=fmod(c+0.25, 360.);
/* Swapbuffers */
glXSwapBuffers(Xdisplay, GLXWindowHandle);
}
/*------------------------------------------------------------------------
Program entry point
------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
/* instead of a triangle I wanted a teapot. GLUT has it.
GLUT is NOT used for window creation, but just the teapot
primitive. Nevertheless it must be initialized */
glutInit(&argc, argv);
createTheWindow();
createTheRenderContext();
while (updateTheMessageQueue()) {
redrawTheWindow();
}
return 0;
}