Почему glCreateShader возвращает 0 (OpenGL ES)

Модератор: Модераторы

Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение StarikPro » 15.02.2015 21:22:18

Привет всем!

Вобщем копаюсь в API OpenGL. Убил безрезультатно выходные разбираясь с шейдерами для OpenGL ES.
В идеале хотелось вывести картину для начала, но до картинок мне пока видимо как до китая раком. :evil: .
Либы libEGL.dll и libGLESv2.dll подключены, OpenGL ES API также прогружено и вроде как валидно.
Подскажите, люди добрые, пожалуста, куда двигать мысли?????



Код: Выделить всё

program Test1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes,
  SysUtils,
  gles20,
  glu,
  Glut
  { you can add units after this };

const
  // простой шейдер вершин
  SimpleVertexShader: AnsiString =
    '#version 330 core' + #$0d + #$0a +
    // Input vertex data, different for all executions of this shader.
    'layout(location = 0) in vec3 vertexPosition_modelspace;' + #$0d + #$0a +
    'layout(location = 1) in vec3 vertexColor;' + #$0d + #$0a +
    // Output data ; will be interpolated for each fragment.
    'out vec3 fragmentColor;' + #$0d + #$0a +
    // Values that stay constant for the whole mesh.
    'uniform mat4 MVP;' + #$0d + #$0a +
    'void main(){'+ #$0d + #$0a +
       // Output position of the vertex, in clip space : MVP * position
       'gl_Position =  MVP * vec4(vertexPosition_modelspace,1);' + #$0d + #$0a +
       // The color of each vertex will be interpolated
       // to produce the color of each fragment
       'fragmentColor = vertexColor;' + #$0d + #$0a +
    '}';
  // простой фрагментный шейдер для вывода цветных вершин
  SimpleFragmentShaderColor: AnsiString =
    '#version 330 core' + #$0d + #$0a +
    // Interpolated values from the vertex shaders
    'in vec3 fragmentColor;'+ #$0d + #$0a +
    // Ouput data
    'out vec3 color;' + #$0d + #$0a +
    'void main(){' + #$0d + #$0a +
       // Output color = color specified in the vertex shader,
       // interpolated between all 3 surrounding vertices
       'color = fragmentColor;' + #$0d + #$0a +
    '}';


var
  window: int32;
  arg_c: int32;
  chars: AnsiString;
  pch: PAnsiChar;
  ProgramID: GLInt;


function LoadShader(const DataVertex, DataFragment: PAnsiChar): boolean;
var
  VertexShaderID: GLuint;
  FragmentShaderID: GLuint;
  resGL: GLInt;
  InfoLogLength: int32;
begin
   // Create the shaders
   VertexShaderID := glCreateShader(GL_VERTEX_SHADER);
   FragmentShaderID := glCreateShader(GL_FRAGMENT_SHADER);
  try

     // Compile Vertex Shader
     glShaderSource(VertexShaderID, 1, Ppchar(@DataVertex), nil);
     glCompileShader(VertexShaderID);

     // Check Vertex Shader
     glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, @resGL);
     glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, @InfoLogLength);
     if ( InfoLogLength > 0 ) or (resGL = 0) then
      exit(false);

     // Compile Fragment Shader
     glShaderSource(FragmentShaderID, 1, Ppchar(@DataFragment), nil);
     glCompileShader(FragmentShaderID);

     // Check Fragment Shader
     glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, @resGL);
     glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, @InfoLogLength);
     if ( InfoLogLength > 0 ) or (resGL = 0) then
      exit(false);

     // Link the program
     ProgramID := glCreateProgram();
     glAttachShader(ProgramID, VertexShaderID);
     glAttachShader(ProgramID, FragmentShaderID);
     glLinkProgram(ProgramID);

     // Check the program
     glGetProgramiv(ProgramID, GL_LINK_STATUS, @resGL);
     glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, @InfoLogLength);
     if ( InfoLogLength > 0 ) or (resGL = 0) then
      exit(false);

  finally
     glDeleteShader(VertexShaderID);
     glDeleteShader(FragmentShaderID);
  end;
end;

procedure Display; cdecl;
begin
  glClearColor(0.0, 0.0, 0.4, 0.0);
  glutSwapBuffers();
end;

begin
  chars := 'Test1.exe';
  // Установка размеров и положения окна
  glutInitWindowSize(640, 480);
  glutInitWindowPosition(0, 0);
  arg_c := 1;
  pch := @chars[1];
  glutInit(@arg_c , @pch);
  window := glutCreateWindow(pch);
  if window = 0 then
    exit;

  glutInitDisplayMode(GLUT_RGBA or GLUT_DOUBLE);
  glutSetWindow(window);
  // Регистрация вызываемых функций
  glutDisplayFunc(@Display);
  // Грузим шейдер
  LoadShader(@SimpleVertexShader[1], @SimpleFragmentShaderColor[1]);
  // Запуск механизма обработки событий
  glutMainLoop();    

  glutDestroyWindow(window);
end.


StarikPro
новенький
 
Сообщения: 18
Зарегистрирован: 24.08.2014 18:22:08

Re: Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение Mirage » 16.02.2015 04:17:41

А на каком девайсе запускаешь?
На десктопе GLES вроде просто так не заводится. Надо дрова специальные например от АМД или эмулятор.
Mirage
энтузиаст
 
Сообщения: 800
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение StarikPro » 16.02.2015 22:19:59

Девайс NVIDIA GF 710M.
Попробовал стандартное API прогрузить для PC при первом же вызове wglGetProcAddress('glBlendEquationSeparate'); получаю nil. Но ведь ноут достаточно свеж, и даже CS (единственное что запускал за последние годы из 3d игр) на нём идёт. Причём любой вызов wglGetProcAddress возвращает nil, как такое может быть ((( ???
StarikPro
новенький
 
Сообщения: 18
Зарегистрирован: 24.08.2014 18:22:08

Re: Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение zub » 16.02.2015 23:17:16

>>Причём любой вызов wglGetProcAddress возвращает nil, как такое может быть ((( ???
Контекст OpenGL создан? емнип без текущего контекста она nil и должна возвращать
zub
долгожитель
 
Сообщения: 2380
Зарегистрирован: 14.11.2005 23:51:26

Re: Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение StarikPro » 18.02.2015 19:26:17

Извиняюсь за длительное молчание, основная работа съедает всё время...
zub, что означает "Контекст OpenGL создан?" В примерах к книге "OpenGL ES 3.0 Programming Guide, 2nd Edition.pdf" я увидел что вначале необходимо вызывать так же:
Код: Выделить всё
  display_ := eglGetDisplay ( EGL_DEFAULT_DISPLAY );
  if ( display_ = EGL_NO_DISPLAY ) then
    begin
     // Unable to open connection to local windowing system
    exit;
    end;
  if eglInitialize(display_, @major, @minor) = 0 then
    exit;

а понятие контекста - это чистое творение автора утилиты к данной книге построенное на смеси: callback методов разработчика + API ОС и API OpenGL ES.
Вобщем после вызова указанного выше метода я увидел что major = 1, minor = 4, а API шейдеров я пытаюсь использовать минимум из версии 2.0, если даже не 3.0. Т.е. пока я пришёл к выводу что мой ноут для версии GLES>=2 негоден? Но мне непонятно - libGLESv2.dll - эмулятор API GLES и он просто заворачивает на методы в подходящий доступный графический API??? Ели так то теоретически он должен мне предоставить доступ GLES >= v2, т.к. DirectX11 установлен, так же скачал драйвера ориентированные на десктопный OpenGL c официального сайта и SDK к ним с работающими примерами. Вобщем х.з. что делать...
StarikPro
новенький
 
Сообщения: 18
Зарегистрирован: 24.08.2014 18:22:08

Re: Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение Mirage » 19.02.2015 00:37:06

Откуда эта libGLESv2 взялась?
Я использую для эмуляции GL ES 2.0 эмулятор Regal: https://github.com/p3/regal
У него свои .dll, у которым можно зацепиться вместо opengl32.dll или libglesv2.dll.
У меня, правда самая свежая .dll не работает. Но это может быть потому что я запускаю все это через виртуалку с древней XP.
Mirage
энтузиаст
 
Сообщения: 800
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение StarikPro » 20.02.2015 18:47:04

Спасибо большое Mirage! Буду щупать :)
StarikPro
новенький
 
Сообщения: 18
Зарегистрирован: 24.08.2014 18:22:08

Re: Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение StarikPro » 28.02.2015 18:23:02

И снова всем привет!
В общем разобрался сам )
Пишу для справки желающим начать писать кросплатформенные приложения на OpenGL ES >= 2.0 API.
Для отладки под Windows необходимо скачать соответственно библиотеки libGLESv2.dll и libEGL.dll проекта ANGLE:
https://code.google.com/p/angleproject/. Если не желаете билдить самоcтоятельно то библиотеки можно взять, например, отсюда: https://drive.google.com/file/d/0By3tpQMnuHz-M1RtVll1ejFjdWM/edit?pli=1. Лично я их взял от установленного у меня QT. Сейчас авторы проекта ANGLE
активно работают над введением поддержки версии GL ES 3.

Отвечаю на свои вопросы:
1. glCreateShader возвращает 0 потому что не проинициализирован контекст GL ES. Я это реализовал (по примеру из книги "OpenGL ES 3.0 Programming Guide, 2nd Edition") таким образом:
Код: Выделить всё
const
  /// esCreateWindow flag - RGB color buffer
  ES_WINDOW_RGB = 0;
  /// esCreateWindow flag - ALPHA color buffer
  ES_WINDOW_ALPHA = 1;
  /// esCreateWindow flag - depth buffer
  ES_WINDOW_DEPTH = 2;
  /// esCreateWindow flag - stencil buffer
  ES_WINDOW_STENCIL = 4;
  /// esCreateWindow flat - multi-sample buffer
  ES_WINDOW_MULTISAMPLE = 8;

type
  PEGLWindow = ^TEGLWindow;
  TEGLWindow = record
     /// Window width
    width: GLint;

    /// Window height
    height: GLint;

    /// Window handle
    hWnd: EGLNativeWindowType;
  end;

  TESContext = record
     /// Put your user data here...
     userData: Pointer;

     eglWindow: PEGLWindow;

     /// EGL display
     eglDisplay: EGLDisplay;

     /// EGL context
     eglContext: EGLContext;

     /// EGL surface
     eglSurface: EGLSurface;

     /// Callbacks
     EGLDrawFunc: TEGLDrawFunc;
     EGLKeyFunc: TEGLKeyFunc;
     EGLUpdateFunc: TEGLUpdateFunc;
  end;

///
// CreateEGLContext()
//
//    Creates an EGL rendering context and all associated elements
//
//      flags  - bitwise or of window creation flags
//          ES_WINDOW_ALPHA       - specifies that the framebuffer should have alpha
//          ES_WINDOW_DEPTH       - specifies that a depth buffer should be created
//          ES_WINDOW_STENCIL     - specifies that a stencil buffer should be created
//          ES_WINDOW_MULTISAMPLE - specifies that a multi-sample buffer should be created
//
function CreateEGLContext (
  EGLWindow: PEGLWindow; // данная структура содержит необходимый хэндл окна в которое будет выводится изображение; вместо нее можно передавать сам хэндл - кому как удобно
  flags: GLuint
  ): PESContext;
var
   numConfigs: EGLint;
   majorVersion: EGLint;
   minorVersion: EGLint;
   display: EGLDisplay;
   context: EGLContext;
   surface: EGLSurface;
   config: EGLConfig;
   contextAttribs: array[0..3] of EGLint;
   attribList: array[0..14] of EGLint;
begin
  contextAttribs[0] := EGL_CONTEXT_CLIENT_VERSION;
  contextAttribs[1] := 2;
  contextAttribs[2] := EGL_NONE;
  contextAttribs[3] := EGL_NONE;

  attribList[0] := EGL_RED_SIZE;   attribList[1] := 5;
  attribList[2] := EGL_GREEN_SIZE; attribList[3] := 6;
  attribList[4] := EGL_BLUE_SIZE;  attribList[5] := 5;
  attribList[6] := EGL_ALPHA_SIZE; if (flags and ES_WINDOW_ALPHA) > 0 then attribList[7] := 8 else attribList[7] := EGL_DONT_CARE;
  attribList[8] := EGL_DEPTH_SIZE; if (flags and ES_WINDOW_DEPTH) > 0 then attribList[9] := 8 else attribList[9] := EGL_DONT_CARE;
  attribList[10] := EGL_STENCIL_SIZE; if (flags and ES_WINDOW_STENCIL) > 0 then attribList[11] := 8 else attribList[11] := EGL_DONT_CARE;
  attribList[12] := EGL_SAMPLE_BUFFERS; if (flags and ES_WINDOW_MULTISAMPLE) > 0 then attribList[13] := 1 else attribList[13] := 0;
  attribList[14] := EGL_NONE;


  // Get Display
  display := eglGetDisplay(EGLWindow^.hWnd); // EGL_DEFAULT_DISPLAY
  if ( display = EGL_NO_DISPLAY ) then
    exit(nil);

  // Initialize EGL
  if (eglInitialize(display, @majorVersion, @minorVersion) = EGL_FALSE ) then
    exit(nil);

   // Get configs
  if (eglGetConfigs(display, nil, 0, @numConfigs) = EGL_FALSE ) then
    exit(nil);

  // Choose config
  if ( eglChooseConfig(display, attribList, @config, 1, @numConfigs) = EGL_FALSE ) then
    exit(nil);

  // Create a surface
  surface := eglCreateWindowSurface(display, config, EGLNativeWindowType(EGLWindow^.hWnd), nil);
  if ( surface = EGL_NO_SURFACE ) then
    exit(nil);

  // Create a GL context
  context := eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs );
  if ( context = EGL_NO_CONTEXT ) then
    exit(nil);

  // Make the context current
  if ( eglMakeCurrent(display, surface, surface, context) = EGL_FALSE ) then
    exit(nil);

  new(Result);
  Result^.eglDisplay := display;
  Result^.eglSurface := surface;
  Result^.eglContext := context;
  Result^.eglWindow := EGLWindow;
end;


2. Инициализация выполняется на API библиотеки libEGL.dll
3. eglInitialize возвращает не версию поддерживаемого GL ES, как я думал ранее, а версию библиотеки libEGL.dll
4. В проект необходимо включать только gles20, а не gl и glext, т.к. вторые это чистый десктопный OpenGL и их нельзя путать.

Всем терпения и удачи!
StarikPro
новенький
 
Сообщения: 18
Зарегистрирован: 24.08.2014 18:22:08

Re: Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение Art!P » 21.11.2015 21:53:30

Извиняюсь, что раскопал эту тему :roll:
И чем всё кончилось?
Имею проблему с антиалиасингом в OpenGL на GTK2 (модуль GTKGLEXT). Mультисэмплинг не работает.
что-то пытаюсь но всё грустно, буферы сэмплинга - 0. В ГЛУТе не пробовал пока.
Скинул код http://pastebin.com/ZZcuksei
Аватара пользователя
Art!P
новенький
 
Сообщения: 27
Зарегистрирован: 28.07.2012 14:37:53

Re: Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение Mirage » 22.11.2015 23:52:33

А мультисэмплинг и не нужен. SMAA сейчас рулит.
Mirage
энтузиаст
 
Сообщения: 800
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение StarikPro » 29.11.2015 13:30:01

>Art!P
В OpenGL ES 2.0 делается всё ручкам, а именно через шейдеры. Возможно в третьей версии есть соответствующее апи, но я не копался и оставил это пока до лучших времён - как только полноценно в ANGLE его добавят. Для сглаживания я использую MSAA, а также (опционально) сцену рисую в текстуру большего размера чем вьюпорт, а затем при выводе в меньшего размера вьюпорт итоговая картинка отлично сглаживается:
Код: Выделить всё
      glViewport(0, 0, FFrameBufferLarge^.Width, FFrameBufferLarge^.Height);
      glBindFramebuffer(GL_FRAMEBUFFER, FFrameBufferLarge^.FrameBufferName);
      DrawScene;
      glBindBuffer(GL_ARRAY_BUFFER, 0);
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
      // draw from texture to screen
      glViewport(0, 0, FWindowWidth, FWindowHeight);
      glBindFramebuffer(GL_FRAMEBUFFER, 0);
      DrawSmoothQuad(FFrameBufferLarge);

Метод DrawSmoothQuad:
Код: Выделить всё
procedure DrawSmoothQuad(FrameBuffer: PFrameBuffer);
const
   QUAD_VERTEXES: array[0..5] of TVec3f = (
      (x:-1.0; y:-1.0; z:0.0),
      (x: 1.0; y:-1.0; z:0.0),
      (x:-1.0; y: 1.0; z:0.0),
      (x:-1.0; y: 1.0; z:0.0),
      (x: 1.0; y:-1.0; z:0.0),
      (x: 1.0; y: 1.0; z:0.0)
   );
begin
  // Off depth test/Выключить тест глубины
  glDisable(GL_DEPTH_TEST);
  FSmoothShader.UseProgram;
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, FrameBuffer^.RenderedTexture);
   //glClearColor(0.0, 0.0, 0.0, 1.0);
  glVertexAttribPointer(
    FSmoothShader.PosCoord^.Location,     // attribute. No particular reason for 1, but must match the layout in the shader.
    3,                                    // size
    GL_FLOAT,                             // type
    GLboolean(GL_FALSE),                  // normalized?
    sizeof(TVec3f), // stride
    @QUAD_VERTEXES[0]                  // array buffer offset
  );
  glDrawArrays(GL_TRIANGLES, 0, 6);
  glDisableVertexAttribArray(0);
  {$ifdef DEBUG_BS}
  CheckErrorGL('DrawSmoothQuad', TTypeCheckError.tcNone, -1);
  {$endif}
end;

Фрагментный шейдер для для этого трюка:
Код: Выделить всё
precision mediump float;
uniform sampler2D s_texture;
varying vec2 v_texCoord;

void main()
{
   gl_FragColor = texture2D( s_texture,  v_texCoord);
}

Вертексный шейдер:
Код: Выделить всё
// input parameters
attribute vec3 a_position;
// outout parameters
varying vec2 v_texCoord;

void main()
{
   gl_Position =  vec4(a_position, 1);
   v_texCoord = (a_position.xy + vec2(1,1))/2.0;
}

Для MSAA использую шейдеры основной принцип работы которых - это усреднение цвета текселя относительно соседних. Я беру 4 соседних и этого достаточно. Есть и другие техники, но мне пока хватает.
Фрагментный шейдер MSAA:
Код: Выделить всё
precision mediump float;
uniform sampler2D s_texture;
varying vec2 v_texCoord;

void main()
{
   gl_FragColor = texture2D( s_texture,  v_texCoord);
   float bias = 0.00095;
   gl_FragColor += texture2D( s_texture, vec2(v_texCoord.x+bias, v_texCoord.y  ) );
   gl_FragColor += texture2D( s_texture, vec2(v_texCoord.x-bias, v_texCoord.y  ) );
   gl_FragColor += texture2D( s_texture, vec2(v_texCoord.x,   v_texCoord.y+bias) );
   gl_FragColor += texture2D( s_texture, vec2(v_texCoord.x,   v_texCoord.y-bias) );
   gl_FragColor = gl_FragColor/5.0;
}

Вертексный шейдер MSAA:
Код: Выделить всё
// input parameters
attribute vec3 a_position;
// outout parameters
varying vec2 v_texCoord;

void main()
{
   gl_Position =  vec4(a_position, 1);
   v_texCoord = (a_position.xy + vec2(1,1))/2.0;
}


И ещё добавлю, что если хочешь использовать OpenGL ES, то забудь про glBegin, glEnd, glPushMatrix и т.д...
StarikPro
новенький
 
Сообщения: 18
Зарегистрирован: 24.08.2014 18:22:08

Re: Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение Mirage » 29.11.2015 18:13:01

StarikPro писал(а): сцену рисую в текстуру большего размера чем вьюпорт, а затем при выводе в меньшего размера вьюпорт итоговая картинка отлично сглаживается:


Это что-то типа supersampling получается. Самый затратный способ антиальясинга. Даже для десктопов мало подходит.

StarikPro писал(а):Фрагментный шейдер MSAA:

Это не MSAA. Это сглаживание текстуры. Причем сглаживание всего, а не того, что надо, что замыливает картинку. И тоже сильно нагружает шину памяти.
Это на мобильных устройствах тестировалось в смысле производительности?
Mirage
энтузиаст
 
Сообщения: 800
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение StarikPro » 29.11.2015 20:05:20

Mirage писал(а):Это не MSAA

Pure MSAA в GLES 2.0 вроде не представлен (по крайней мере на десктопе мне не удалось его включить во время инициализации контекста) и любой другой так же... всё отдано на откуп разработчикам софта через щейдеры.
Сглаживание, в т.ч. ужиманием размеров, во-первых, у меня опционально, во вторых, для моих проектов не так критично, т.к. я отображаю в основном статические сцены.
Менее затратных способов сглаживания для GLES20 я не нашёл.
Сглаживание FXAA, считающийся одним из самых оптимальных, так же выполняется шейдером в пост обработке на текстуре и математики там больше чем в моём. Я же использую самый простой способ, чем он нагруженнее других? Вы знаете другие способы/пути более оптимальные?
На мобильных платформах пока не тестировал, т.к. применяю в базовом проекте для ПК. Но когда-нибудь обязательно попытаюсь )

Добавлено спустя 39 минут 29 секунд:
Mirage писал(а):что замыливает картинку

Я беру очень малое смещение и совместно с ужиманием даёт неплохой результат
StarikPro
новенький
 
Сообщения: 18
Зарегистрирован: 24.08.2014 18:22:08

Re: Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение Mirage » 02.12.2015 02:38:12

SMAA как раз и является менее затратным.
Хотя на мобильных девайсах это надо проверять.
Но теоретически должно быть лучше, чем жрущее шину сглаживание.
Mirage
энтузиаст
 
Сообщения: 800
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Почему glCreateShader возвращает 0 (OpenGL ES)

Сообщение StarikPro » 05.12.2015 10:19:20

Mirage писал(а):SMAA как раз и является менее затратным.
Хотя на мобильных девайсах это надо проверять.
Но теоретически должно быть лучше, чем жрущее шину сглаживание.

Поправьте если я не прав. Но в шейдере SMAA предложенным автором (к сожаленью не могу его сходу найти), если мне не изменяет память, так же используется выборка сэмплером соседних текселей как и в моём шейдере. Только в моём далее выполняется тупое усреднение цвета, а в SMAA определение границ и т. д. Исходя из этого я предположил что мой шейдер MSAA менее нагружает ГПУ. Может вы имели ввиду хардварные реализации от производителей ГПУ? Об этом в GLES 2 мечтать не приходится :(
StarikPro
новенький
 
Сообщения: 18
Зарегистрирован: 24.08.2014 18:22:08

След.

Вернуться в Графика

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

Рейтинг@Mail.ru